1095: [ZJOI2007]Hide 捉迷藏
阿新 • • 發佈:2018-11-06
題意
給了一顆 個節點的樹,起初樹上節點的顏色都是黑的,有兩種操作,第一種是把某個節點變色,黑的變白,白的變黑,第二種是查詢當前樹上最遠的兩個黑色節點的距離,不存在黑點輸出 ;
題解
這題本來是一道經典的點分治題,但是在做機房dalao給的題時,學了一種更優秀的做法:用線段樹維護樹上直徑;先DFS一遍得到樹的DFS序,以DFS序建一棵線段樹;現在考慮,如果得到了兩棵子樹內的直徑,兩棵子樹合併起來會是怎樣,結果是顯然的,新直徑的兩個端點必然是原先四個直徑端點中的兩個,那麼就可以兩兩列舉這兩個點找到新的直徑,這就是線段樹的 函式,因為這個做法顯然能夠推廣到任意兩個樹上聯通塊的合併上;如果再預處理 表 找 的話,這個做法的複雜度為 ,並且支援修改和子樹查詢;
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,p,Q,cnt,TIME;
int head[N],Log[N<<1],ST[22][N<<1],V[N<<1],ID[N<<1],dep[N],S[N],dfn[N],low[N];
char ins[5];
struct Data {
int u,v;
Data () {}
Data (int a,int b) :u(a),v(b) {}
}G[N<<2],ANS;
int LCA(int u,int v) {
if(ID[u]>ID[v]) swap(u,v);
int k=Log[ID[v]-ID[u]+1];
if(dep[ST[k][ID[u]]]<dep[ST[k][ID[v]-(1<<k)+1]]) return ST[k][ID[u]];
return ST[k][ID[v]-(1<<k)+1];
}
Data operator +(Data A,Data B) {
if(!A.u) return B;
if(!B.u) return A;
int d1,d2,d3,d4,d5,d6,MAXV;
d1=dep[A.u]+dep[A.v]-2*dep[LCA(A.u,A.v)];
d2=dep[B.u]+dep[B.v]-2*dep[LCA(B.u,B.v)];
d3=dep[A.u]+dep[B.v]-2*dep[LCA(A.u,B.v)];
d4=dep[B.u]+dep[A.v]-2*dep[LCA(B.u,A.v)];
d5=dep[A.u]+dep[B.u]-2*dep[LCA(A.u,B.u)];
d6=dep[A.v]+dep[B.v]-2*dep[LCA(A.v,B.v)];
MAXV=max(max(max(max(max(d1,d2),d3),d4),d5),d6);
if(MAXV==d1) return Data(A.u,A.v);
if(MAXV==d2) return Data(B.u,B.v);
if(MAXV==d3) return Data(A.u,B.v);
if(MAXV==d4) return Data(B.u,A.v);
if(MAXV==d5) return Data(A.u,B.u);
return Data(A.v,B.v);
}
#define L o<<1
#define R o<<1|1
struct SegmentTree {
bool On[N<<2];
void Build(int l,int r,int o) {
if(l==r) {
On[o]=true;
G[o]=Data(S[l],S[l]);
return;
}
int mid=l+r>>1;
Build(l,mid,L); Build(mid+1,r,R);
G[o]=G[L]+G[R];
}
void Modify(int l,int r,int o,int pos) {
if(l==r) {
On[o]^=1;
if(On[o]) G[o]=Data(S[l],S[l]);
else G[o]=Data(0,0);
return;
}
int mid=l+r>>1;
if(pos<=mid) Modify(l,mid,L,pos);
else Modify(mid+1,r,R,pos);
G[o]=G[L]+G[R];
}
void Query(int l,int r,int o,int ql,int qr) {
if(ql<=l&&r<=qr) {
ANS=ANS+G[o];
return;
}
int mid=l+r>>1;
if(ql<=mid) Query(l,mid,L,ql,qr);
if(qr>mid) Query(mid+1,r,R,ql,qr);
}
}SgT;
struct Edge {
int to,last;
Edge () {}
Edge (int a,int b) :to(a),last(b) {}
}edge[N<<1];
void ADD(int a,int b) {
edge[++p]=Edge(b,head[a]); head[a]=p;
edge[++p]=Edge(a,head[b]); head[b]=p;
}
void DFS(int u,int fa) {
dfn[u]=++TIME; S[TIME]=u; ID[u]=++cnt; V[cnt]=u;
for(int i=head[u];i;i=edge[i].last) {
int v=edge[i].to;
if(v!=fa) {
dep[v]=dep[u]+1; DFS(v,u);
V[++cnt]=u;
}
}
low[u]=TIME;
}
void Prepare() {
Log[0]=-1;
for(int i=1;i<=cnt;++i) Log[i]=Log[i>>1]+1;
for(int i=1;i<=cnt;++i) ST[0][i]=V[i];
for(int i=1;(1<<i)<=cnt;++i) {
for(int j=1;j+(1<<i)-1<=cnt;++j) {
if(dep[ST[i-1][j]]<dep[ST[i-1][j+(1<<(i-1))]]) ST[i][j]=ST[i-1][j];
else ST[i][j]=ST[i-1][j+(1<<(i-1))];
}
}
}
int main() {
scanf("%d",&n);
for(int i=1;i<n;++i) {
int u,v; scanf("%d%d",&u,&v);
ADD(u,v);
}
DFS(1,0);
Prepare();
SgT.Build(1,n,1);
scanf("%d",&Q);
while(Q--) {
int x; scanf("%s",ins);
if(ins[0]=='C') scanf("%d",&x),SgT.Modify(1,n,1,dfn[x]);
else {
if(!G[1].u) puts("-1");
else printf("%d\n",dep[G[1].u]+dep[G[1].v]-2*dep[LCA(G[1].u,G[1].v)]);
}
}
return 0;
}