首页 > 其他分享 >P10238 [yLCPC2024] F. PANDORA PARADOXXX

P10238 [yLCPC2024] F. PANDORA PARADOXXX

时间:2024-08-18 19:27:44浏览次数:10  
标签:PARADOXXX ch return P10238 int nowmax yLCPC2024 find dis

这里主要是了解一下套路,首先说一下树的直径的性质。

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;
}

标签:PARADOXXX,ch,return,P10238,int,nowmax,yLCPC2024,find,dis
From: https://www.cnblogs.com/zhengchenxi/p/18365950

相关文章

  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    题目传送门前置知识树链剖分|树的直径|最近公共祖先|并查集解法正着删边不太可做,考虑离线下来反着加边。一个显而易见的结论:设点集\(A\)的直径的两个端点为\(u_{1},v_{1}\),另一个点集\(B\)的直径的两个端点为\(u_{2},v_{2}\),则\(A\bigcupB\)的直径端点一定是......
  • 题解:P10234 [yLCPC2024] B. 找机厅
    题意简述给你一个长\(n\)宽\(m\)的\(01\)迷宫,从\((1,1)\)开始要走到\((n,m)\)。如果能走那么输出最短路和路径(路径用\(LRUD\)表示),否则输出\(-1\)。有\(t\)组数据。如果当前格子是\(0\)那么你只能走到\(1\)的格子,反之亦然。思路考虑使用\(BFS\),每次走......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX
    P10238[yLCPC2024]F.PANDORAPARADOXXX并查集维护连通性+结论+数据结构维护距离题目的操作是删边通常复杂,并且不强制在线,所以离线倒过来加边。题目要求的就是当前所有连通块的直径的最大值,考虑加边后两个连通块合并后直径的变化。有结论:合并后的连通块的直径两端点一定是合......
  • 【题解】P10235 [yLCPC2024] C. 舞萌基本练习
    P10235舞萌基本练习题解思路看到最大值最小首先考虑二分答案。由于答案满足单调性,可以二分不优美度的最大值,也就是逆序对数的最大值。我们在每次增加一个元素的时候都要求解当前区间的逆序对数,所以不能用归并排序求逆序对数,考虑树状数组解法。如果不会树状数组求逆序对,请出......
  • P10234 [yLCPC2024] B. 找机厅 题解
    题目简述给定一个$n$行$m$列的$01$矩阵,每次可以花费$1$的时间移动到邻近的上下左右的四个格子,求从$(1,1)$点到$(n,m)$的最少时间,并给出具体路径。题目分析第一问易发现是BFS模板题,在这里不多说。第二问我们首先考虑正着记录,即记录每一个点转移到了哪一个点,但......
  • P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解
    分析考虑时光倒流。对于需要合并的两个连通块\(x,y\),其合并之后的最远点对距离一定是合并之前的两组点对中产生的。在合并的时候枚举点对,取距离最大值即可。由于我们是倒着来的,所有连通块的最远点对距离最大值不减,所以能直接在合并之后取最大值。维护连通块用并查集即可。复杂......
  • P10237 [yLCPC2024] E. Latent Kindom 题解
    分析一眼了非最优解。考虑二分答案。对于二分出来的中位数\(x\),到\(a_i\)和\(a_j\)里边又去二分。得到两个序列中不超过\(x\)的数的数量。若这个数量\(cnt\ge\lceil\frac{len_{i}+len_{j}}{2}\rceil\),则\(x\)可能成为中位数,然后继续二分即可。把序列离散化,复杂度......