题意
给了一颗 个节点的树,起初树上节点的颜色都是黑的,有两种操作,第一种是把某个节点变色,黑的变白,白的变黑,第二种是查询当前树上最远的两个黑色节点的距离,不存在黑点输出 ;
题解
这题本来是一道经典的点分治题,但是在做机房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;
}