1. 程式人生 > 實用技巧 >P4092 [HEOI2016/TJOI2016]樹 題解

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\n",ans[i]);
	return 0;
}