点分树借鉴了点分治的思想,将分治过程当中具备父子关系的重心连边ios
造成了一颗高度为 \(logn\) 的树数组
这样每一次分治时,咱们就不用从新去找重心,直接沿着点分树向上跳便可数据结构
和点分治相比,点分树能够支持多组询问spa
并且还可以进行修改操做,能够解决一些强制在线的题目rest
点分树有两个性质:code
\(1\)、原树上任意两点 \(p,q\) 在点分树上的 \(lca\) 必定在 \(p\) 到 \(q\) 的路径上排序
\(2\)、点分树的树高是 \(logn\) 级别的游戏
第一个性质决定了咱们能够经过向上跳父亲来处理与路径有关的信息get
第二个性质则决定了咱们这么作不会 \(T\)string
通常来讲,点分树的题都须要咱们在节点上维护两个数据结构
一个存储全部子树对本身的贡献,另外一个存储全部子树对父亲的贡献,计算答案时要容斥计算
由于树高是 \(logn\) 的,因此这么作的空间复杂度为 \(nlogn\)
二维数组确定开不下,因此常常用 \(vector\) 来实现
查询到点 \(x\) 距离小于等于 \(k\) 的全部点的权值之和,强制在线,支持修改
根据点分树的第一个性质,咱们能够枚举其它点与点 \(x\) 的 \(lca\) 是哪个点,这个 \(lca\) 必定是点 \(x\) 在点分树上的祖先节点
假设当前枚举到的点是 \(y\)
若 \(y\) 知足条件,则有 \(dis(x,lca)+dis(y,lca) \leq k\)
因此只须要查询到 \(lca\) 的距离小于等于 \(k-dis(x,lca)\) 的点便可
还要支持修改操做,能够用数状数组维护
可是这样会有重复的状况
由于咱们只是简单地知足了距离关系,因此 \(x\) 和 \(y\) 在原树上的 \(lca\) 不必定是当前的节点,还有多是当前点在点分树上的子节点
所以要把子节点中距离 \(lca\) 的距离小于等于 \(k-dis(c,lca)\) 的贡献删除,这和点分治中的容斥是同样的
可是要注意的是,点分树中的父子节点在原树上基本没有什么关系,因此不能直接在儿子节点的数状数组中把这个贡献减去
而要另开一个数状数组记录儿子节点在点分树中的子树对其父亲的贡献
查询时,咱们从当前点开始一直跳点分树的父亲,容斥计算贡献
修改时,也是暴力跳父亲,在数状数组上加入当前贡献与以前贡献的差
对于一开始就有的价值,咱们直接做为修改操做处理
时间复杂度 \(mlog^2n\)
#include<cstdio> #include<cstring> #include<iostream> #include<vector> #include<algorithm> #define rg register inline int read(){ rg int x=0,fh=1; rg char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') fh=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*fh; } const int maxn=1e5+5; int h[maxn],tot=1,n,m,latans; struct asd{ int to,nxt; }b[maxn<<1]; void ad(rg int aa,rg int bb){ b[tot].to=bb; b[tot].nxt=h[aa]; h[aa]=tot++; } int siz[maxn],dep[maxn],fa[maxn],son[maxn]; void dfs1(rg int now,rg int lat){ siz[now]=1; dep[now]=dep[lat]+1; fa[now]=lat; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat) continue; dfs1(u,now); siz[now]+=siz[u]; if(son[now]==0 || siz[u]>siz[son[now]]) son[now]=u; } } int tp[maxn],val[maxn]; void dfs2(rg int now,rg int top){ tp[now]=top; if(son[now]) dfs2(son[now],top); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==son[now] || u==fa[now]) continue; dfs2(u,u); } } int getlca(rg int xx,rg int yy){ while(tp[xx]!=tp[yy]){ if(dep[tp[xx]]<dep[tp[yy]]) std::swap(xx,yy); xx=fa[tp[xx]]; } return dep[xx]<dep[yy]?xx:yy; } int getdis(rg int xx,rg int yy){ return dep[xx]+dep[yy]-2*dep[getlca(xx,yy)]; } int rt,totsiz,maxsiz[maxn]; bool vis[maxn]; void getroot(rg int now,rg int lat){ siz[now]=1,maxsiz[now]=0; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getroot(u,now); siz[now]+=siz[u]; maxsiz[now]=std::max(maxsiz[now],siz[u]); } maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]); if(maxsiz[now]<maxsiz[rt]) rt=now; } int lb(rg int xx){ return xx&-xx; } struct BIT{ std::vector<int> tr; int trsiz; void init(rg int now){ for(rg int i=0;i<=now;i++) tr.push_back(0); trsiz=now; } void ad(rg int wz,rg int val){ wz=std::min(wz+1,trsiz); for(rg int i=wz;i<=trsiz;i+=lb(i)){ tr[i]+=val; } } int cx(rg int wz){ wz=std::min(wz+1,trsiz); rg int nans=0; for(rg int i=wz;i>0;i-=lb(i)){ nans+=tr[i]; } return nans; } }tr1[maxn],tr2[maxn]; int newfa[maxn]; void getsiz(rg int now,rg int lat){ siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getsiz(u,now); siz[now]+=siz[u]; } } void predfs(rg int now){ vis[now]=1; getsiz(now,0); rg int tmp=siz[now]+3; tr1[now].init(tmp); tr2[now].init(tmp); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(vis[u]) continue; totsiz=siz[u],rt=0; getroot(u,now); newfa[rt]=now; predfs(rt); } }//构建点分树 void updat(rg int now,rg int nval){ for(rg int i=now;i;i=newfa[i]){ tr1[i].ad(getdis(now,i),nval); } for(rg int i=now;newfa[i];i=newfa[i]){ tr2[i].ad(getdis(newfa[i],now),nval); } }//更新答案 int solve(rg int now,rg int k){ rg int nans=tr1[now].cx(k); for(rg int i=now;newfa[i];i=newfa[i]){ rg int tmp=getdis(newfa[i],now); if(k>=tmp) nans+=tr1[newfa[i]].cx(k-tmp)-tr2[i].cx(k-tmp); } return nans; }//查询答案 int main(){ memset(h,-1,sizeof(h)); n=read(),m=read(); for(rg int i=1;i<=n;i++) val[i]=read(); rg int aa,bb,cc; for(rg int i=1;i<n;i++){ aa=read(),bb=read(); ad(aa,bb),ad(bb,aa); } dfs1(1,0); dfs2(1,1); maxsiz[0]=0x3f3f3f3f,rt=0,totsiz=n; getroot(1,0); predfs(rt); for(rg int i=1;i<=n;i++) updat(i,val[i]); for(rg int i=1;i<=m;i++){ aa=read(),bb=read(),cc=read(); bb^=latans,cc^=latans; if(aa==0) printf("%d\n",latans=solve(bb,cc)); else { updat(bb,cc-val[bb]); val[bb]=cc; } } return 0; }
查询点 \(u\) 到全部年龄在区间 \([l,r]\) 中妖怪的距离,强制在线
一样能够在点分树上套数据结构解决
设当前的点为 \(x\),当前点的儿子节点为 \(u\)
那么该点对答案的贡献就是\(x\)子树中年龄在 \([l,r]\) 之间的妖怪到 \(x\) 的距离之和 - \(u\) 子树中年龄在 \([l,r]\) 之间的妖怪到 \(x\) 的距离之和+(\(x\)子树中年龄在 \([l,r]\) 之间的妖怪个数- \(u\) 子树中年龄在 \([l,r]\) 之间的妖怪个数) \(\times\) 查询点到节点 \(x\) 的距离
由于没有修改操做,因此直接用 \(vector\) ,\(vector\) 中存储妖怪的年龄以及妖怪到当前点的距离
\(vector\) 要开两个,一个记录对当前点的贡献,一个记录对父亲节点的贡献
对于年龄的限制,咱们在建好点分树后直接把 \(vector\) 中的元素按照年龄从小到大排序
而后记录一个前缀和,查询时二分便可
而妖怪的个数就是二分时下标之差
距离之和直接暴力跳父亲算一下就好了
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #include<iostream> #define rg register inline int read(){ rg int x=0,fh=1; rg char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') fh=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*fh; } const int maxn=1e6+5; int h[maxn],tot=1; struct asd{ int to,nxt,val; }b[maxn]; void ad(rg int aa,rg int bb,rg int cc){ b[tot].to=bb; b[tot].nxt=h[aa]; b[tot].val=cc; h[aa]=tot++; } int n,q,maxage,x[maxn],siz[maxn],fa[maxn],dep[maxn],son[maxn]; long long dis[maxn]; void dfs1(rg int now,rg int lat){ fa[now]=lat; dep[now]=dep[lat]+1; siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat) continue; dis[u]=dis[now]+b[i].val; dfs1(u,now); siz[now]+=siz[u]; if(siz[son[now]]<siz[u]) son[now]=u; } } int tp[maxn]; void dfs2(rg int now,rg int top){ tp[now]=top; if(son[now]) dfs2(son[now],top); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==son[now] || u==fa[now]) continue; dfs2(u,u); } } int getlca(rg int xx,rg int yy){ while(tp[xx]!=tp[yy]){ if(dep[tp[xx]]<dep[tp[yy]]) std::swap(xx,yy); xx=fa[tp[xx]]; } return dep[xx]<dep[yy]?xx:yy; } long long getdis(rg int xx,rg int yy){ return dis[xx]+dis[yy]-2LL*dis[getlca(xx,yy)]; } int maxsiz[maxn],totsiz,rt; bool vis[maxn]; void getroot(rg int now,rg int lat){ maxsiz[now]=0,siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getroot(u,now); siz[now]+=siz[u]; maxsiz[now]=std::max(maxsiz[now],siz[u]); } maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]); if(maxsiz[rt]>maxsiz[now]) rt=now; } struct Node{ int age; long long dis; Node(){} Node(rg int aa,rg long long bb){ age=aa,dis=bb; } friend bool operator <(const Node& A,const Node& B){ return A.age<B.age; } }; std::vector<Node> vec[2][maxn]; void getsiz(rg int now,rg int lat){ siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getsiz(u,now); siz[now]+=siz[u]; } } int newfa[maxn]; void predfs(rg int now){ vis[now]=1; getsiz(now,0); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(!vis[u]){ rt=0,totsiz=siz[u]; getroot(u,now); newfa[rt]=now; predfs(rt); } } } void updat(rg int now){ for(rg int i=now;i;i=newfa[i]){ vec[0][i].push_back(Node(x[now],getdis(i,now))); } for(rg int i=now;newfa[i];i=newfa[i]){ vec[1][i].push_back(Node(x[now],getdis(newfa[i],now))); } } long long latans; int nowsiz; long long cx(rg int op,rg int now,rg int l,rg int r){ rg int nl=std::lower_bound(vec[op][now].begin(),vec[op][now].end(),Node(l,0))-vec[op][now].begin()-1; rg int nr=std::upper_bound(vec[op][now].begin(),vec[op][now].end(),Node(r,0))-vec[op][now].begin()-1; nowsiz=nr-nl; if(nr<0) return 0; if(nl<0) return vec[op][now][nr].dis; return vec[op][now][nr].dis-vec[op][now][nl].dis; } long long solve(rg int now,rg int l,rg int r){ rg long long nans=cx(0,now,l,r); rg int sizfa,siznow; for(rg int i=now;newfa[i];i=newfa[i]){ nans+=cx(0,newfa[i],l,r); sizfa=nowsiz; nans-=cx(1,i,l,r); siznow=nowsiz; nans+=1LL*(sizfa-siznow)*getdis(newfa[i],now); } return nans; } int main(){ memset(h,-1,sizeof(h)); n=read(),q=read(),maxage=read(); for(rg int i=1;i<=n;i++) x[i]=read(); rg int aa,bb,cc,l,r; for(rg int i=1;i<n;i++){ aa=read(),bb=read(),cc=read(); ad(aa,bb,cc); ad(bb,aa,cc); } dfs1(1,0); dfs2(1,1); maxsiz[0]=0x3f3f3f3f,rt=0,totsiz=n; getroot(1,0); predfs(rt); for(rg int i=1;i<=n;i++) updat(i); for(rg int i=1;i<=n;i++){ std::sort(vec[0][i].begin(),vec[0][i].end()); std::sort(vec[1][i].begin(),vec[1][i].end()); for(rg int j=1;j<vec[0][i].size();j++) vec[0][i][j].dis+=vec[0][i][j-1].dis; for(rg int j=1;j<vec[1][i].size();j++) vec[1][i][j].dis+=vec[1][i][j-1].dis; } for(rg int i=1;i<=q;i++){ aa=read(),bb=read(),cc=read(); l=std::min((bb+latans)%maxage,(cc+latans)%maxage); r=std::max((bb+latans)%maxage,(cc+latans)%maxage); latans=solve(aa,l,r); printf("%lld\n",latans); } return 0; }
这道题实际上就是让咱们寻找带权重心
假设当前的点为 \(x\),\(x\) 的子节点为 \(u\),\(u\) 和 \(x\) 之间的边权为 \(len\)
若是 \(x\) 子树内一点 \(u\) 更优,那么必定有 \((totsiz-siz[u]) \times len - siz[u] \times len <0\)
由于边权是正的,因此就有 \(2siz[u]>totsiz\)
显然知足这个条件的儿子只有一个
由于每个点的度数不会超过 \(20\)
所以能够在点分树上暴力地寻找
注意必定要在点分树上找,不要跑到原树上去找,不然复杂度就假了
若是用 \(st\) 表 \(O(1)\) 求 \(lca\),那么复杂度就是 \(20qlog^2n\)
但实际上跑得尚未树剖快
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> #include<iostream> #define rg register inline int read(){ rg int x=0,fh=1; rg char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') fh=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*fh; } const int maxn=2e5+5; int h[maxn],tot=1; struct asd{ int to,nxt,val; }b[maxn<<1]; void ad(rg int aa,rg int bb,rg int cc){ b[tot].to=bb; b[tot].nxt=h[aa]; b[tot].val=cc; h[aa]=tot++; } int n,q,x[maxn],siz[maxn],eul[maxn],dfnc,dep[maxn],lg[maxn<<1],st[maxn<<1][22],rk[maxn<<1]; long long dis[maxn]; void dfs(rg int now,rg int lat){ dep[now]=dep[lat]+1; eul[now]=++dfnc; rk[dfnc]=now; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat) continue; dis[u]=dis[now]+b[i].val; dfs(u,now); rk[++dfnc]=now; } } void prest(){ for(rg int i=2;i<=dfnc;i++) lg[i]=lg[i>>1]+1; for(rg int i=1;i<=dfnc;i++) st[i][0]=rk[i]; for(rg int j=1;j<=20;j++){ for(rg int i=1;i+(1<<j)-1<=dfnc;i++){ if(dep[st[i][j-1]]<dep[st[i+(1<<(j-1))][j-1]]) st[i][j]=st[i][j-1]; else st[i][j]=st[i+(1<<(j-1))][j-1]; } } } int getlca(rg int xx,rg int yy){ xx=eul[xx],yy=eul[yy]; if(xx>yy) std::swap(xx,yy); rg int nk=lg[yy-xx+1]; return dep[st[xx][nk]]<dep[st[yy-(1<<nk)+1][nk]]?st[xx][nk]:st[yy-(1<<nk)+1][nk]; } long long getdis(rg int xx,rg int yy){ return dis[xx]+dis[yy]-2LL*dis[getlca(xx,yy)]; } int maxsiz[maxn],totsiz,rt; bool vis[maxn]; void getroot(rg int now,rg int lat){ maxsiz[now]=0,siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getroot(u,now); siz[now]+=siz[u]; maxsiz[now]=std::max(maxsiz[now],siz[u]); } maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]); if(maxsiz[rt]>maxsiz[now]) rt=now; } void getsiz(rg int now,rg int lat){ siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getsiz(u,now); siz[now]+=siz[u]; } } int newfa[maxn]; std::vector<std::pair<int,int> > g[maxn]; void predfs(rg int now){ vis[now]=1; getsiz(now,0); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(!vis[u]){ rt=0,totsiz=siz[u]; getroot(u,now); newfa[rt]=now; g[now].push_back(std::make_pair(u,rt)); predfs(rt); } } } long long sum1[maxn],sum2[maxn]; int siz1[maxn],siz2[maxn]; void updat(rg int now,rg int val){ for(rg int i=now;i;i=newfa[i]){ sum1[i]+=1LL*getdis(now,i)*val; siz1[i]+=val; } for(rg int i=now;newfa[i];i=newfa[i]){ sum2[i]+=1LL*getdis(now,newfa[i])*val; siz2[i]+=val; } } long long cx(rg int now){ rg long long nans=sum1[now]; for(rg int i=now;newfa[i];i=newfa[i]){ nans+=sum1[newfa[i]]; nans-=sum2[i]; nans+=1LL*getdis(newfa[i],now)*(siz1[newfa[i]]-siz2[i]); } return nans; } long long solve(rg int now){ rg long long tmp=cx(now); for(rg int i=0;i<g[now].size();i++){ if(cx(g[now][i].first)<tmp) return solve(g[now][i].second); } return tmp; } int main(){ memset(h,-1,sizeof(h)); n=read(),q=read(); rg int aa,bb,cc; for(rg int i=1;i<n;i++){ aa=read(),bb=read(),cc=read(); ad(aa,bb,cc); ad(bb,aa,cc); } dfs(1,0); prest(); maxsiz[0]=0x3f3f3f3f,rt=0,totsiz=n; getroot(1,0); predfs(rt); memset(vis,0,sizeof(vis)); rt=0,totsiz=n; getroot(1,0); for(rg int i=1;i<=q;i++){ aa=read(),bb=read(); updat(aa,bb); printf("%lld\n",solve(rt)); } return 0; }
和其它点分树的题目同样,对于每个节点咱们开两个堆,防止同一个子树内的节点对父亲节点作屡次贡献
一个堆里存点分树中 \(u\) 的子树全部点到点分树中 \(u\) 的父亲的距离
另外一个堆里存点分树中 \(u\) 的全部儿子对 \(u\) 贡献的最大值
那么答案就是第二个堆中最大值与次大值之和
加入贡献时,咱们直接扔到大根堆里就能够了
删除贡献时,咱们再开一个堆,堆里面存储全部已经删除过的元素
查询时只要不断弹两个堆的堆顶,直到一个堆为空或者两个堆堆顶的元素不相同为止
#include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<iostream> #define rg register inline int read(){ rg int x=0,fh=1; rg char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') fh=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*fh; } const int maxn=1e5+5; int h[maxn],tot=1; struct asd{ int to,nxt; }b[maxn<<1]; void ad(rg int aa,rg int bb){ b[tot].to=bb; b[tot].nxt=h[aa]; h[aa]=tot++; } int n,q,siz[maxn],fa[maxn],dep[maxn],son[maxn]; void dfs1(rg int now,rg int lat){ fa[now]=lat; dep[now]=dep[lat]+1; siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat) continue; dfs1(u,now); siz[now]+=siz[u]; if(siz[son[now]]<siz[u]) son[now]=u; } } int tp[maxn]; void dfs2(rg int now,rg int top){ tp[now]=top; if(son[now]) dfs2(son[now],top); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==son[now] || u==fa[now]) continue; dfs2(u,u); } } int getlca(rg int xx,rg int yy){ while(tp[xx]!=tp[yy]){ if(dep[tp[xx]]<dep[tp[yy]]) std::swap(xx,yy); xx=fa[tp[xx]]; } return dep[xx]<dep[yy]?xx:yy; } int getdis(rg int xx,rg int yy){ return dep[xx]+dep[yy]-2*dep[getlca(xx,yy)]; } int maxsiz[maxn],totsiz,rt; bool vis[maxn]; void getroot(rg int now,rg int lat){ maxsiz[now]=0,siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getroot(u,now); siz[now]+=siz[u]; maxsiz[now]=std::max(maxsiz[now],siz[u]); } maxsiz[now]=std::max(maxsiz[now],totsiz-siz[now]); if(maxsiz[rt]>maxsiz[now]) rt=now; } void getsiz(rg int now,rg int lat){ siz[now]=1; for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(u==lat || vis[u]) continue; getsiz(u,now); siz[now]+=siz[u]; } } int newfa[maxn]; void predfs(rg int now){ vis[now]=1; getsiz(now,0); for(rg int i=h[now];i!=-1;i=b[i].nxt){ rg int u=b[i].to; if(!vis[u]){ rt=0,totsiz=siz[u]; getroot(u,now); newfa[rt]=now; predfs(rt); } } } char s[maxn]; struct Splay{ std::priority_queue<int> q1; std::priority_queue<int> q2; void updat(){ for(;!q1.empty() && !q2.empty() && q1.top()==q2.top();){ q1.pop(); q2.pop(); } } void insert(rg int val){ q1.push(val); } void pop(rg int val){ q2.push(val); } int getmax(){ updat(); return q1.top(); } int getsec(){ updat(); rg int now1=q1.top();q1.pop(); updat(); rg int now2=q1.top();q1.pop(); q1.push(now1),q1.push(now2); return now2; } int size(){ return q1.size()-q2.size(); } }ansnow[maxn],ansfa[maxn],ans; void updat(rg int now){ vis[now]^=1; if(vis[now]==0){ if(ansnow[now].size()>=2) ans.pop(ansnow[now].getmax()+ansnow[now].getsec()); ansnow[now].insert(0); if(ansnow[now].size()>=2) ans.insert(ansnow[now].getmax()+ansnow[now].getsec()); for(rg int i=now;newfa[i];i=newfa[i]){ if(ansnow[newfa[i]].size()>=2) ans.pop(ansnow[newfa[i]].getmax()+ansnow[newfa[i]].getsec()); rg int ndis=getdis(now,newfa[i]); if(ansfa[i].size()) ansnow[newfa[i]].pop(ansfa[i].getmax()); ansfa[i].insert(ndis); if(ansfa[i].size()) ansnow[newfa[i]].insert(ansfa[i].getmax()); if(ansnow[newfa[i]].size()>=2) ans.insert(ansnow[newfa[i]].getmax()+ansnow[newfa[i]].getsec()); } } else { if(ansnow[now].size()>=2) ans.pop(ansnow[now].getmax()+ansnow[now].getsec()); ansnow[now].pop(0); if(ansnow[now].size()>=2) ans.insert(ansnow[now].getmax()+ansnow[now].getsec()); for(rg int i=now;newfa[i];i=newfa[i]){ if(ansnow[newfa[i]].size()>=2) ans.pop(ansnow[newfa[i]].getmax()+ansnow[newfa[i]].getsec()); rg int ndis=getdis(now,newfa[i]); if(ansfa[i].size()) ansnow[newfa[i]].pop(ansfa[i].getmax()); ansfa[i].pop(ndis); if(ansfa[i].size()) ansnow[newfa[i]].insert(ansfa[i].getmax()); if(ansnow[newfa[i]].size()>=2) ans.insert(ansnow[newfa[i]].getmax()+ansnow[newfa[i]].getsec()); } } } int cnt; int main(){ memset(h,-1,sizeof(h)); n=read(); rg int aa,bb; for(rg int i=1;i<n;i++){ aa=read(),bb=read(); ad(aa,bb); ad(bb,aa); } dfs1(1,0); dfs2(1,1); maxsiz[0]=0x3f3f3f3f,rt=0,totsiz=n; getroot(1,0); predfs(rt); q=read(); memset(vis,0,sizeof(vis)); for(rg int i=1;i<=n;i++){ for(rg int j=i;newfa[j];j=newfa[j]){ ansfa[j].insert(getdis(i,newfa[j])); } } for(rg int i=1;i<=n;i++){ ansnow[i].insert(0); if(newfa[i] && ansfa[i].size()) ansnow[newfa[i]].insert(ansfa[i].getmax()); } for(rg int i=1;i<=n;i++){ if(ansnow[i].size()>=2) ans.insert(ansnow[i].getmax()+ansnow[i].getsec()); } cnt=n; for(rg int i=1;i<=q;i++){ scanf("%s",s+1); if(s[1]=='G'){ if(cnt==0) printf("-1\n"); else if(cnt==1) printf("0\n"); else printf("%d\n",ans.getmax()); } else { aa=read(); if(vis[aa]) cnt++; else cnt--; updat(aa); } } return 0; }