Jiajia和Wind是一對恩愛的夫妻,而且他們有不少孩子。ios
某天,Jiajia、Wind和孩子們決定在家裏玩捉迷藏遊戲。git
他們的家很大且構造很奇特,由N個屋子和N-1條雙向走廊組成,ide
這N-1條走廊的分佈使得任意兩個屋子都互相可達。spa
遊戲是這樣進行的,孩子們負責躲藏,Jiajia負責找,而Wind負責操縱這N個屋子的燈。code
在起初的時候,全部的燈都沒有被打開。blog
每一次,孩子們只會躲藏在沒有開燈的房間中,遊戲
可是爲了增長刺激性,孩子們會要求打開某個房間的電燈或者關閉某個房間的電燈。ip
爲了評估某一次遊戲的複雜性,get
Jiajia但願知道可能的最遠的兩個孩子的距離(即最遠的兩個關燈房間的距離)。input
咱們將以以下形式定義每一種操做:
輸入文件hide.in第一行包含一個整數N,表示房間的個數,房間將被編號爲1,2,3…N的整數。
接下來N-1行每行兩個整數a, b,表示房間a與房間b之間有一條走廊相連。
接下來一行包含一個整數Q,表示操做次數。.
接着Q行,每行一個操做,如上文所示。
對於每個操做Game,輸出一個非負整數到hide.out,表示最遠的兩個關燈房間的距離。
若只有一個房間是關着燈的,輸出0;若全部房間的燈都開着,輸出-1。
8
1 2
2 3
3 4
3 5
3 6
6 7
6 8
7
G
C 1
G
C 2
G
C 1
G
4
3
3
4
對於20%的數據,N≤50, Q≤100;
對於60%的數據,N≤3000, Q≤10000;
對於100%的數據,N≤100000, Q≤500000。
動態詢問多組點對信息,因此使用動態點分治。
根據點分治的基本思路,
對於一個重心,咱們一般記錄通過重心的路徑來統計答案。
這裏咱們沿用這種思路,設亮着的房間爲白點,黑着的房間爲黑點。
對於某個重心\(w\),記錄每一個子樹\(v\)中的黑點到\(w\)的最長鏈(每一個子樹只能貢獻一個,避免重複)。
計算該重心對答案的貢獻時直接取堆\(c[w]\)中的最大值+次大值便可。
因爲有刪除操做,咱們要可以迅速更新最長鏈的方法。
因而,咱們對每一個節點\(v\),再開一個堆\(up\),記錄以\(v\)爲根的子樹到\(v\)的\(parent\)的最長鏈。
注意:
上面的\(parent\)指的是點分樹上的父親。
而後再維護一個\(ans\)堆記錄答案。
還有一個注意事項,因爲要支持堆中的刪除操做,須要額外建一個堆維護刪除信息。
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<iomanip> #include<cstdlib> #include<queue> #define MAXN 0x7fffffff typedef long long LL; const int N=100005; using namespace std; inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;} int h[N],cnt; struct Edge{int to,next;}g[N<<1]; void AddEdge(int x,int y){g[++cnt].to=y,g[cnt].next=h[x],h[x]=cnt;} int fa[N],dep[N]; int size[N],son[N],tp[N]; void Dfs1(int x){ size[x]=1; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(to==fa[x])continue; fa[to]=x,dep[to]=dep[x]+1; Dfs1(to),size[x]+=size[to]; if(size[to]>size[son[x]])son[x]=to; } } void Dfs2(int x,int top){ tp[x]=top; if(son[x])Dfs2(son[x],top); for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(to==fa[x]||to==son[x])continue; Dfs2(to,to); } } int LCA(int x,int y){ while(tp[x]^tp[y]){ if(dep[tp[x]]<dep[tp[y]])y=fa[tp[y]]; else x=fa[tp[x]]; } return dep[x]<dep[y]?x:y; } int dis(int x,int y){return dep[x]+dep[y]-2*dep[LCA(x,y)];} struct Heap{ priority_queue<int>q,del; void push(int x){q.push(x);} void erase(int x){del.push(x);} int top(){ while(del.size()&&q.top()==del.top())q.pop(),del.pop(); return q.top(); } void Pop(){ while(del.size()&&q.top()==del.top())q.pop(),del.pop(); q.pop(); } int sec(){ int tmp=top();Pop(); int x=top();push(tmp); return x; } int size(){return q.size()-del.size();} }c[N],up[N],ans; int n,num,sum,prt[N]; int rt,sz[N],mx[N]; bool vis[N],light[N]; void to_ans(int v,bool f){ if(c[v].size()>1){ int x=c[v].top()+c[v].sec(); f?ans.push(x):ans.erase(x); } } void Explore(int x,int fa,int top){ up[top].push(dis(x,prt[top])); for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(vis[to]||to==fa)continue; Explore(to,x,top); } } void Get_size(int x,int fa) { sz[x]=1; for(int i=h[x];i;i=g[i].next) { int to=g[i].to; if(to==fa||vis[to]) continue; Get_size(to,x); sz[x]+=sz[to]; } } void Get_root(int x,int fa){ mx[x]=0; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(to==fa||vis[to])continue; Get_root(to,x); mx[x]=max(mx[x],sz[to]); } mx[x]=max(mx[x],sum-sz[x]); if(mx[rt]>mx[x])rt=x; } void Solve(int x){ vis[x]=1,c[x].push(0); for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(vis[to]||to==prt[x])continue; Get_size(to,0),sum=sz[to]; rt=0,Get_root(to,0); prt[rt]=x; Explore(rt,0,rt); c[x].push(up[rt].top()); Solve(rt); } to_ans(x,1); } void Change(int x,bool f){ f?(num--):(num++); to_ans(x,0); f?c[x].erase(0):c[x].push(0); to_ans(x,1); for(int i=x;prt[i];i=prt[i]){ to_ans(prt[i],0); if(up[i].size())c[prt[i]].erase(up[i].top()); f?up[i].erase(dis(x,prt[i])):up[i].push(dis(x,prt[i])); if(up[i].size())c[prt[i]].push(up[i].top()); to_ans(prt[i],1); } } int main(){ num=n=Getint(); for(int i=1;i<n;i++){ int x=Getint(),y=Getint(); AddEdge(x,y),AddEdge(y,x); } dep[1]=1,Dfs1(1),Dfs2(1,1); sum=n,mx[0]=n+1; Get_size(1,0),Get_root(1,0); Solve(rt); int m=Getint(); for(int i=1;i<=m;i++){ char ch=getchar(); while(ch!='C'&&ch!='G')ch=getchar(); if(ch=='C'){ int x=Getint(); light[x]^=1; Change(x,light[x]); }else{ if(!num)cout<<"-1\n"; else if(num==1)cout<<"0\n"; else cout<<ans.top()<<'\n'; } } return 0; }