1. 程式人生 > >【SPOJ】QTREE6(Link-Cut-Tree)

【SPOJ】QTREE6(Link-Cut-Tree)

string algorithm getc 個數 AC 強制 main struct 優化

【SPOJ】QTREE6(Link-Cut-Tree)

題面

Vjudge

題解

很神奇的一道題目
我們發現點有黑白兩種,又是動態加邊/刪邊
不難想到\(LCT\)

最爆力的做法,顯然是每次修改單點顏色的時候
暴力修改當前點和它的父親以及兒子之間的連邊狀態

但是這樣顯然是假的(菊花樹了解一下)

怎麽優化呢?
對於每次操作,我們考慮如何只修改一次。
對於樹上的一個結點,如果只修改一次,顯然是修改和其父親的狀態。
那麽,我們在考慮\(LCT\)的連邊操作的時候,
如果當前點變色,那麽就只修改和它父親的連邊。
這樣怎麽算答案呢?
如果我們確定樹是一棵有根樹
那麽,我們只需要找到當前點深度最淺的父親
這個父親在當前顏色的樹上的兒子個數顯然就是答案

所以,我們只需要每次只修改當前點和其父親的關系就行了。
但是要註意一個問題,因為強制是有根樹了。
所以打死都不能有\(makeroot\)操作
所以\(link,cut\)之類的都要魔改一發了。。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue> using namespace std; #define ll long long #define RG register #define MAX 111111 #define ls (t[x].ch[0]) #define rs (t[x].ch[1]) inline int read() { RG int x=0,t=1;RG char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if
(ch=='-')t=-1,ch=getchar(); while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar(); return x*t; } struct Line{int v,next;}e[MAX<<1]; int h[MAX],cnt=1; inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;} struct Link_Cut_Tree { struct Node { int ch[2],ff; int size,sum; int rev; }t[MAX]; bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;} void pushup(int x){t[x].sum=t[ls].sum+t[rs].sum+t[x].size+1;} void rotate(int x) { int y=t[x].ff,z=t[y].ff; int k=t[y].ch[1]==x; if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z; t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y; t[x].ch[k^1]=y;t[y].ff=x; pushup(y);pushup(x); } void Splay(int x) { while(!isroot(x)) { int y=t[x].ff,z=t[y].ff; if(!isroot(y)) (t[y].ch[0]==x)^(t[z].ch[0]==y)?rotate(x):rotate(y); rotate(x); } pushup(x); } void access(int x) { for(int y=0;x;y=x,x=t[x].ff) { Splay(x);t[x].size+=t[rs].sum-t[y].sum; rs=y;pushup(x); } } void link(int x,int y){if(!y)return;access(y);Splay(x);Splay(y);t[x].ff=y;t[y].size+=t[x].sum;pushup(y);} void cut(int x,int y){if(!y)return;access(x);Splay(x);ls=t[ls].ff=0;pushup(x);} int findroot(int x){access(x);Splay(x);while(ls)x=ls;Splay(x);return x;} }LCT[2]; int n,m,fa[MAX],c[MAX]; void dfs(int u,int ff) { for(int i=h[u];i;i=e[i].next) { int v=e[i].v;if(v==ff)continue; LCT[1].link(v,u);fa[v]=u; dfs(v,u); } } int main() { n=read(); for(int i=1;i<=n;++i)c[i]=1; for(int i=1,u,v;i<n;++i)u=read(),v=read(),Add(u,v),Add(v,u); dfs(1,0); m=read(); while(m--) { int opt=read(),x=read(); if(opt)LCT[c[x]].cut(x,fa[x]),c[x]^=1,LCT[c[x]].link(x,fa[x]); else { LCT[c[x]].access(x); int ff=LCT[c[x]].findroot(x); if(c[ff]==c[x])printf("%d\n",LCT[c[x]].t[ff].sum); else printf("%d\n",LCT[c[x]].t[LCT[c[x]].t[ff].ch[1]].sum); } } return 0; }

【SPOJ】QTREE6(Link-Cut-Tree)