题解:动态点分治
建立点分树,每个节点维护两个容器
记录本子树内到点分树父亲节点的路径长度集合
和自己所有子树内节点到自己的最长路径构成的集合
//语文不好,凑合着看吧QWQ
支持删除,所以用双堆来维护即可
同时维护全局堆统计答案
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<vector> using namespace std; const int maxn=100009; const int inf=1000000000; int T; int n,m; int cntb; int c[maxn]; int cntedge; int head[maxn]; int to[maxn<<1],nex[maxn<<1]; void Addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } int f[maxn][20]; int dep[maxn]; void Dfs(int now,int fa){ f[now][0]=fa; dep[now]=dep[fa]+1; for(int i=head[now];i;i=nex[i]){ if(to[i]==fa)continue; Dfs(to[i],now); } } void LCAinit(){ for(int j=1;j<=19;++j){ for(int i=1;i<=n;++i){ f[i][j]=f[f[i][j-1]][j-1]; } } } int Getlca(int u,int v){ if(dep[u]<dep[v])swap(u,v); for(int j=19;j>=0;--j){ if(dep[f[u][j]]>=dep[v])u=f[u][j]; } if(u==v)return u; for(int j=19;j>=0;--j){ if(f[u][j]!=f[v][j]){ u=f[u][j];v=f[v][j]; } } return f[u][0]; } inline int Getdist(int u,int v){ int lca=Getlca(u,v); return dep[u]+dep[v]-2*dep[lca]; } int nowsiz,root; int vis[maxn]; int g[maxn]; int siz[maxn]; int divfa[maxn]; void Getroot(int x,int fa){ siz[x]=1;g[x]=0; for(int i=head[x];i;i=nex[i]){ if(to[i]==fa)continue; if(vis[to[i]])continue; Getroot(to[i],x); siz[x]+=siz[to[i]]; g[x]=max(g[x],siz[to[i]]); } g[x]=max(g[x],nowsiz-siz[x]); if(g[x]<g[root])root=x; } int h[maxn]; priority_queue<int>q[maxn][4]; void Cle(int x,int y){ while((!q[x][y].empty())&&(!q[x][y+1].empty())){ if(q[x][y].top()==q[x][y+1].top()){ q[x][y].pop();q[x][y+1].pop(); }else{ break; } } } void Geth(int x){ Cle(x,0); if(c[x]){ if(q[x][0].size()-q[x][1].size()<2){ h[x]=0; }else{ int tm=q[x][0].top();q[x][0].pop(); Cle(x,0); h[x]=tm+q[x][0].top();q[x][0].push(tm); } }else{ if(q[x][0].size()-q[x][1].size()==0){ h[x]=0; }else if(q[x][0].size()-q[x][1].size()==1){ h[x]=q[x][0].top(); }else{ int tm=q[x][0].top();q[x][0].pop(); Cle(x,0); h[x]=tm+q[x][0].top();q[x][0].push(tm); } } } void Getsiz(int x,int fa){ siz[x]=1; for(int i=head[x];i;i=nex[i]){ if(vis[to[i]])continue; if(to[i]==fa)continue; Getsiz(to[i],x); siz[x]+=siz[to[i]]; } } //0,1 2,3 void Getq2(int x,int fa,int dd,int rt){ q[rt][2].push(dd); for(int i=head[x];i;i=nex[i]){ if(to[i]==fa)continue; if(vis[to[i]])continue; Getq2(to[i],x,dd+1,rt); } } void Sol(int x){ vis[x]=1; //维护q[2],q[3]; Getsiz(x,0); for(int i=head[x];i;i=nex[i]){ if(vis[to[i]])continue; nowsiz=siz[to[i]];root=0; Getroot(to[i],x); divfa[root]=x; Getq2(to[i],x,1,root); q[x][0].push(q[root][2].top()); } Geth(x); q[0][0].push(h[x]); for(int i=head[x];i;i=nex[i]){ if(vis[to[i]])continue; nowsiz=siz[to[i]];root=0; Getroot(to[i],x); Sol(root); } } int main(){ scanf("%d",&n); for(int i=1;i<=n-1;++i){ int x,y; scanf("%d%d",&x,&y); Addedge(x,y); Addedge(y,x); } Dfs(1,0); LCAinit(); g[0]=inf;nowsiz=n; Getroot(1,0); Sol(root); cntb=n; scanf("%d",&T); while(T--){ char opty=getchar(); while(opty!=‘C‘&&opty!=‘G‘)opty=getchar(); int x; if(opty==‘C‘){ scanf("%d",&x); if(c[x]==0){ c[x]=1;--cntb; int y=x; while(y){ q[0][1].push(h[y]); Geth(y); q[0][0].push(h[y]); if(divfa[y]){ Cle(y,2); q[divfa[y]][1].push(q[y][2].top()); int tm=Getdist(divfa[y],x); q[y][3].push(tm); Cle(y,2); if(q[y][2].size()-q[y][3].size()>0)q[divfa[y]][0].push(q[y][2].top()); } y=divfa[y]; } }else{ c[x]=0;++cntb; int y=x; while(y){ q[0][1].push(h[y]); Geth(y); q[0][0].push(h[y]); if(divfa[y]){ Cle(y,2); if(q[y][2].size()-q[y][3].size()>0)q[divfa[y]][1].push(q[y][2].top()); int tm=Getdist(divfa[y],x); q[y][2].push(tm); Cle(y,2); q[divfa[y]][0].push(q[y][2].top()); } y=divfa[y]; } } }else{ if(cntb==0){ printf("%d\n",-1); }else if(cntb==1){ printf("%d\n",0); }else{ Cle(0,0); printf("%d\n",q[0][0].top()); } } } return 0; }