P10238 [yLCPC2024] F. PANDORA PARADOXXX

zhengchenxi發表於2024-08-18

這裡主要是瞭解一下套路,首先說一下樹的直徑的性質。

1.任何一個點到它所在的聯通塊中距離最遠的點一定是樹的直徑兩點之一。
2.兩個連通塊合併以後,新的樹的直徑一定為原先兩個連通塊中樹的直徑中的兩個。

瞭解完這個,我們來看這道題,根據樹的直徑的性質,我們可以來維護連通塊,那一個難點就是刪邊很難處理,但它是離線操作,我們就可以考慮時光倒流,倒著處理,把刪邊改為加邊。

維護連通性,我們就可以用並查集,然後再不斷合併即可。

點選檢視程式碼
#include<bits/stdc++.h>
using namespace std;


#define int long long
const int N=5e5+10;
int n,m;


int read()
{
	int f=1,s=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){s=(s<<1)+(s<<3)+(ch^48);ch=getchar();}
	return f*s;
} 

int fa[N],s[N][2];
struct lmy
{
	int x,y,z;
}e[N];

int h[N],nxt[N<<1],to[N<<1],w[N<<1],tot;
void add(int x,int y,int dt)
{
	to[++tot]=y;
	nxt[tot]=h[x];
	w[tot]=dt;
	h[x]=tot;
}

int f[N][25],dep[N],dis[N];
void dfs(int u,int fat)
{
	dep[u]=dep[fat]+1,f[u][0]=fat;
	for(int i=1;i<24;++i) f[u][i]=f[f[u][i-1]][i-1];
	
	for(int i=h[u];i;i=nxt[i])
	{
		int v=to[i];
		if(v==fat) continue;
		dis[v]=dis[u]+w[i];
		dfs(v,u);
	}
	return ;
}

int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	
	for(int i=23;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	
	for(int i=23;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0];
}

int get(int a,int b){return dis[a]+dis[b]-2*dis[lca(a,b)];}

int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}

int ans[N],nowmax;
int Mx[N];
void merge(int x,int y)
{
	fa[y]=x;
	int maxx=0;
	int now[10]={s[x][0],s[x][1],s[y][0],s[y][1]};
	for(int i=0;i<4;i++)
	{
		for(int j=0;j<4;j++)
		{
			int nowx=now[i],nowy=now[j];
			int dis=get(nowx,nowy);
			if(dis>maxx)
			{
				maxx=dis,s[x][0]=nowx,s[x][1]=nowy;
				Mx[x]=dis;
			}
		}	
	}
	
	nowmax=max(nowmax,Mx[x]);
	return ;
}

int d[N],vis[N];
void solve()
{
	n=read(),m=read(),tot=0,nowmax=0;
	for(int i=1;i<=n;i++)
	{
		fa[i]=i,s[i][0]=s[i][1]=i;
		h[i]=dep[i]=dis[i]=0;
		ans[i]=0,Mx[i]=0;
		for(int j=0;j<=24;++j) f[i][j]=0;
		vis[i]=0;
	}
	for(int i=1;i<=n-1;i++)
	{
		int a=read(),b=read(),dt=read();
		add(a,b,dt),add(b,a,dt);
		e[i]={a,b,dt};
	}
	dfs(1,0);
	for(int i=1;i<=m;++i) d[i]=read(),vis[d[i]]=1;
	
	for(int i=1;i<n;++i)
	{
		if(vis[i]) continue;
		int x=e[i].x,y=e[i].y;
		if(dep[x]>dep[y]) swap(x,y);
		merge(find(x),find(y));
	}
	for(int i=m;i>=1;i--)
	{
		int x=e[d[i]].x,y=e[d[i]].y;
		if(dep[x]>dep[y]) swap(x,y);
		ans[i]=nowmax;
		merge(find(x),find(y));
	}
	for(int i=1;i<=m;++i) cout<<ans[i]<<"\n";
	return ;
}

signed main()
{
	int t=read();
	while(t--)
	{
		solve();
	}
	
	return 0;
}