TJOI/HEOI2016树


\(n,Q1e5\)

线段树轻松A

并查集离线做法

先统计所有的点标记次数

先一遍dfs,若标记,父亲为自己,否则为树上的父亲

询问离线,倒序询问

若查询,直接查并查集父亲

否则减标记,若标记为0,则将并查集父亲设为树上父亲

时间复杂度\(O(nlogn)\)

并查集直接路径压缩才是正确复杂度,因为并查集父亲方向均向上,且代表意思为祖先最近标记点,所以修改时不会错

#include<bits/stdc++.h>
using namespace std;
inline int read(){
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
	return f==1?x:-x;
}
const int N=1e5+4;
int n,Q,c[N],fa[N],uf[N],op[N],uu[N],ans[N];
vector<int>e[N];
void dfs(int x){
	if(c[x])uf[x]=x;
	else uf[x]=fa[x];
	for(auto v:e[x]){
		if(v==fa[x])continue;
		fa[v]=x;
		dfs(v);
	}
}
int find(int x){return uf[x]==x?x:uf[x]=find(uf[x]);}
char ch[4];
int main(){
	n=read();Q=read();
	for(int i=1,u,v;i<n;i++){
		u=read();v=read();
		e[u].push_back(v);e[v].push_back(u);
	}
	c[1]=1;
	for(int i=1;i<=Q;i++){
		scanf("%s",ch);
		op[i]=(ch[0]=='C');
		uu[i]=read();
		if(op[i])c[uu[i]]++;
	}
	dfs(1);
	for(int i=Q;i;i--){
		if(op[i]&&!(--c[uu[i]]))uf[uu[i]]=fa[uu[i]];
		else ans[i]=find(uu[i]);
	}
	for(int i=1;i<=Q;i++)
		if(!op[i])cout<<ans[i]<<"\n";
	return (0-0);
}
posted @ 2020-04-20 11:05  starusc  阅读(94)  评论(0)    收藏  举报