P4092 [HEOI2016/TJOI2016]树 题解

Link

P4092 [HEOI2016/TJOI2016]树

Solve

这道题是一个树剖显然能解决的问题,但是lyz神仙非要离线做懒得写树剖

考虑离线做,一个点把一条链分成两部分,比较类似于删边的操作,对于只有删边,我们就可以考虑倒过来处理,就只有连边了,用并查集来维护

如果最后是被标记过的点,把(fa[])标为自己,否则标记为父节点。

反过来处理,如果询问,直接获取(get(x))就是答案,如果是标记,就(vis[x]--),如果(vis[x])被减到(0)了,说明这条链已经被打通了,就把(fa[x])改为自己的父亲

还有一个细节,1号节点没有父节点,所以在(vis[x]--)的时候要注意一下

Code

#include<bits/stdc++.h>
using namespace std;
const int maxn=100005,maxe=200005;
int N,fa[maxn],Q,ans[maxn],lnk[maxn],cnt,nxt[maxe],son[maxe],vis[maxn],fa_tree[maxn];
struct query{
	char op;
	int x;
}q[maxn];
inline int read(){
	int ret=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
	return ret*f;
}
inline char read_ch(){
	char ch=getchar();
	while(ch!='C'&&ch!='Q')ch=getchar();
	return ch;
}
inline void add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
void DFS(int x,int f){
	fa[x]=(vis[x]||x==1)?x:fa_tree[x];
	for(int j=lnk[x];j;j=nxt[j]){
		if(son[j]==f)continue;
		fa_tree[son[j]]=x;
		DFS(son[j],x);
	}
	return ;
}
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
int main(){
	freopen("P4092.in","r",stdin);
	freopen("P4092.out","w",stdout);
	N=read();Q=read();
	for(int i=1;i<N;i++){
		int x=read(),y=read();
		add_e(x,y);add_e(y,x); 
	}
	for(int i=1;i<=Q;i++){
		q[i].op=read_ch();q[i].x=read();
		if(q[i].op=='C')vis[q[i].x]++;
	}
	DFS(1,0);vis[1]++;
	for(int i=Q;i;i--){
		if(q[i].op=='C'){
			if(!--vis[q[i].x])fa[q[i].x]=fa_tree[q[i].x];
		}
		else {
			ans[++ans[0]]=get(q[i].x);
		}
	}
	for(int i=ans[0];i;i--)printf("%d
",ans[i]);
	return 0;
} 
原文地址:https://www.cnblogs.com/martian148/p/13910585.html