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

P10238 [yLCPC2024] F. PANDORA PARADOXXX 题解

时间:2024-03-09 22:22:38浏览次数:25  
标签:return P10238 题解 int il auto yLCPC2024 find define

分析

考虑时光倒流。

对于需要合并的两个连通块 \(x,y\),其合并之后的最远点对距离一定是合并之前的两组点对中产生的。在合并的时候枚举点对,取距离最大值即可。由于我们是倒着来的,所有连通块的最远点对距离最大值不减,所以能直接在合并之后取最大值。

维护连通块用并查集即可。复杂度 \(O(n\log n)\)。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline
#define pii pair<int,int>
#define x first
#define y second
#define gc getchar()
#define rd read()
#define debug() puts("------------")

namespace yzqwq{
	il int read(){
		int x=0,f=1;char ch=gc;
		while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc;}
		while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
		return x*f;
	}
	il int qmi(int a,int b,int p){
		int ans=1;
		while(b){
			if(b&1) ans=ans*a%p;
			a=a*a%p,b>>=1;
		}
		return ans;
	}
	il auto max(auto a,auto b){return (a>b?a:b);}
	il auto min(auto a,auto b){return (a<b?a:b);}
	il int gcd(int a,int b){
		if(!b) return a;
		return gcd(b,a%b);
	}
	il int lcm(int a,int b){
		return a/gcd(a,b)*b;
	}
	il void exgcd(int a,int b,int &x,int &y){
		if(!b) return x=1,y=0,void(0);
		exgcd(b,a%b,x,y);
		int t=x;
		x=y,y=t-a/b*x;
		return ;
	}
	mt19937 rnd(time(0));
}
using namespace yzqwq;

const int N=5e5+10;
int n,m;
int ne[N<<1],e[N<<1],w[N<<1],h[N],idx;
int fa[N],siz[N],s[N][2];
struct edge{
	int x,y,z;
}E[N];
int d[N],vis[N];
int dep[N],dis[N];
int f[N][25];
int Mx[N];
int ans[N],nowmx;

il void add(int a,int b,int c){
	ne[++idx]=h[a],e[idx]=b,w[idx]=c,h[a]=idx;
}
il void dfs(int now,int fa){
	dep[now]=dep[fa]+1,f[now][0]=fa;
	for(re int i=1;i<24;++i) f[now][i]=f[f[now][i-1]][i-1];
	for(re int i=h[now];i;i=ne[i]){
		int j=e[i];if(j==fa) continue;
		dis[j]=dis[now]+w[i];
		dfs(j,now);
	}
	return ;
}
il int lca(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(re int i=23;i>=0;--i) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
	if(x==y) return x;
	for(re 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];
}
il int diss(int a,int b){
	return dis[a]+dis[b]-2*dis[lca(a,b)];
}
il int find(int x){
	return fa[x]==x?x:fa[x]=find(fa[x]);
}
il void merge(int x,int y){
	fa[y]=x;
	int mx=0;
	int now[10]={s[x][0],s[x][1],s[y][0],s[y][1]};
	for(re int i=0;i<4;++i)
	for(re int j=0;j<4;++j){
		int nowx=now[i],nowy=now[j];
		int Dis=diss(nowx,nowy);
		if(Dis>mx){
			mx=Dis,s[x][0]=nowx,s[x][1]=nowy;
			Mx[x]=Dis;
		}
	}
	nowmx=max(nowmx,Mx[x]);
	return ;
}

il void solve(){
	n=rd,m=rd,idx=0,nowmx=0;
	for(re int i=1;i<=n;++i){
		fa[i]=i,siz[i]=s[i][0]=s[i][1]=0;
		s[i][0]=s[i][1]=i;
		h[i]=dep[i]=dis[i]=0;
		ans[i]=0,Mx[i]=0;
		for(re int j=0;j<=24;++j) f[i][j]=0;
		vis[i]=0;
	}
	for(re int i=1;i<n;++i){
		int a=rd,b=rd,c=rd;
		add(a,b,c),add(b,a,c);
		E[i]={a,b,c};
	}
	dfs(1,0);
	for(re int i=1;i<=m;++i)
		d[i]=rd,vis[d[i]]=1;
	for(re 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(re 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]=nowmx;
		merge(find(x),find(y));
	}
	for(re int i=1;i<=m;++i) cout<<ans[i]<<"\n";
	return ;
}

signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int t=rd;while(t--)
	solve();
	return 0;
}

标签:return,P10238,题解,int,il,auto,yLCPC2024,find,define
From: https://www.cnblogs.com/harmisyz/p/18063491

相关文章

  • P10237 [yLCPC2024] E. Latent Kindom 题解
    分析一眼了非最优解。考虑二分答案。对于二分出来的中位数\(x\),到\(a_i\)和\(a_j\)里边又去二分。得到两个序列中不超过\(x\)的数的数量。若这个数量\(cnt\ge\lceil\frac{len_{i}+len_{j}}{2}\rceil\),则\(x\)可能成为中位数,然后继续二分即可。把序列离散化,复杂度......
  • [ABC219F] Cleaning Robot 题解
    [ABC219F]CleaningRobot题解思路解析要点:将整个图拆分成每一轮的每一个点单独考虑贡献。首先看到\(k\le10^{12}\)发现不能直接枚举\(k\)轮,于是开始找每一轮的规律。首先可以知道,如果操作固定,那么起点和路径上每一个点以及终点的相对位置不会改变。也就是说每一轮的起......
  • CF1583E Moment of Bloom 题解
    题意:给定一张\(n\)个点\(m\)条边无向连通图,以及\(q\)个点对\((a,b)\),出事每条边权值为\(0\)。对于每个点对我们需要找一条从一个点到另一个点的简单路径,将所有边的权值加一。要求构造一种方案使得每条边权值都是偶数。如果不行,输出最少还要几个点对才能满足要求。\(n,m......
  • CF1634E Fair Share 题解
    题意:给定\(m\)个长度为偶数的数组,\(L,R\)是初始为空的两个多重集。将每个数组恰好一半的数放入\(L\),另一半放入\(R\),要求最后\(L=R\),要求构造方案或判断无解。\(m\le10^5,\sumn\le10^5\)。思路:首先我们不难想到,对于同一个数组内相同的值,可以成双除去,所以我们可以......
  • Interval GCD 题解
    题目描述给定一个长度为\(\largen\)的数组\(\largea\),以及\(\largem\)条指令(\(n\leq5\times10^5,m\leq10^5\)),每条指令可能是以下两种之一:“\(\large\operatorname{C\l\r\d}\)”,表示把\(\largea[l],a[l+1],…,a[r]\)都加上\(\larged\)。“\(\large\operatorn......
  • CF1264D2 Beautiful Bracket Sequence (hard version) 题解
    括号深度的本质,其实就是删除若干个字符以后使得左边一半全是(,右边一半全是),最终(的个数的最大值。那么就一定存在一个位置使得在这个位置以及之前的字符中(的个数等于这个字符后)的个数。考虑枚举这个位置,记它左边的(的个数为\(a\)、?的个数为\(x\),右边的)的个数......
  • [CF696B] Puzzles 题解
    首先很好想到要用树形\(dp\)。然后设\(dp_i\)为遍历到第\(i\)个点的期望时间,\(sz_i\)代表\(i\)的子树大小。发现有转移方程:\[dp_i=dp_{fa_i}+1+\sum\limits_{j\infa_i且j\nei}sz_j\timesq\]其中\(q\)为一个常数,代表在排列中\(j\)在\(i\)前的概率。很容易发......
  • 无聊的数列[题解]
    无聊的数列[link1][link2]题目大意给定一个数列\(A\)有两种操作:将数列中\(A_i\)(\(L\leqi\leqR\))加上一个等差数列(首项D公差K)查询数列中第P位数区间加上一个等差数列可以用差分来解决例原序列:000000差分序列:000000等差序列:13579(首项1......
  • 课堂练习 最大值 原题链接+题解
    题目可以去我的洛谷题库看:https://www.luogu.com.cn/problem/U412348(带数据,真难出)题解考虑两种解题方式。由于题目范围较小,可以check+暴力,如果范围大一点,可以check+二分答案。先讲check函数,小学四年级数学书说了,这种问题也被它叫做“铺地砖”问题,计算剪出的正方形数量的方......
  • 一本通 1270 混合背包 题解
    是在hydro上做的,墙裂推荐hydro的一本通题库!链接是:https://hydro.ac/d/ybttk/p/T1270。分析一下,可以分类讨论,处理的时候,零一背包(\(p_i=1\))一个,完全背包(\(p_i=0\))一个,多重背包(\(p_i>1\))一个,状态转移方程不用列的,直接去抄模板就可以啦~代码是这样的捏:#include<bits/st......