题面
SOL
树的直径? 如果有 ∑ ∣ S ∣ ≤ 1 e 6 \sum|S|\le1e6 ∑∣S∣≤1e6 之类的,说不定可以虚树做。然鹅并没有。
另一种 O ( n l o g n ) O(nlogn) O(nlogn)讨论完树中所有路径的做法当然是点分治了。
只是此题需要支持修改,于是记录一下点分治时候的 f a fa fa,每个分治重心维护一个数据结构,我们便有了一个 O ( n l o g n + m l o g 2 n ) O(nlogn+mlog^2n) O(nlogn+mlog2n)的AC算法,点分树(就是动态点分治。。)
具体的,每一个点维护两个堆,一个是每个分治子树该点的最长路径,一个是每一个分治子树中的所有路径,
怎么维护第二个堆? 子树不好找,但是父亲好找呀。可以维护用当前点对应父亲的第二个堆嘛。修改的时候就从当前点看父亲。
PS.这题有点卡常。。最开始居然把分治分错了,难怪TLE。。最后一个点开O2才过
CODE
#include<bits/stdc++.h>
using namespace std;
#define sf scanf
#define pf printf
#define ll long long
#define cs const
#define ri register int
#define db double
#define lb long double
#define gc getchar()
#define in red()
inline int red(){
int num=0,f=1;char c=gc;
for(;!isdigit(c);c=gc)if(c=='-')f=-1;
for(;isdigit(c);c=gc)num=num*10+(c^48);
return num*f;
}
cs int N=1e5+10,M=2e5+10;
int head[N],cnt=0,nxt[M],to[M];
inline void adde(int u,int v){
nxt[++cnt]=head[u];head[u]=cnt;to[cnt]=v;
nxt[++cnt]=head[v];head[v]=cnt;to[cnt]=u;
}
struct heap{
priority_queue<int> a,b;
inline void push(int x){a.push(x);}
inline void pop(int x){if(b.size()<a.size())b.push(x);}
inline int size(){return a.size()-b.size();}
inline int top(){
while(b.size()&&a.top()==b.top())a.pop(),b.pop();
return a.size() ? a.top() : 0;
}
inline int mx(){
int tmp=top();pop(tmp);
int tmp2=top();
return push(tmp),tmp+tmp2;
}
}A,B[N],C[N];
int rt,mx[N],maxn,siz[N],fa[N],dfn[N],st[20][N<<1],Log[N<<1],tot,dep[N],n,m;
bool vis[N],col[N];
void dfs(int u,int f){
st[0][++tot]=u;dfn[u]=tot;dep[u]=dep[f]+1;
for(ri i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==f)continue;
dfs(v,u);
st[0][++tot]=u;
}
}
inline int _min(int a,int b){return dfn[a]<dfn[b] ? a : b;}
inline void init(){
dfs(1,0);Log[1]=0;
for(ri i=2;i<=tot;++i)Log[i]=Log[i>>1]+1;
for(ri i=1;i<=Log[tot];++i){
for(ri j=1;j+(1<<i)-1<=tot;++j){
st[i][j]=_min(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
}
}
inline int qy(int x,int y){
int fx=min(dfn[x],dfn[y]),fy=max(dfn[x],dfn[y]),k=Log[fy-fx+1];
return _min(st[k][fx],st[k][fy-(1<<k)+1]);
}
inline int dist(int x,int y){
return dep[x]+dep[y]-2*dep[qy(x,y)];
}
inline void getrt(int u,int f){
siz[u]=1;mx[u]=0;
for(ri i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==f||vis[v])continue;
getrt(v,u);
siz[u]+=siz[v];
mx[u]=max(mx[u],siz[v]);
}
mx[u]=max(mx[u],maxn-siz[u]);
if(mx[u]<mx[rt])rt=u;
}
inline void divi(int u){
vis[u]=1;
for(ri i=head[u];i;i=nxt[i]){
int v=to[i];
if(vis[v])continue;
maxn=siz[v];rt=0;
getrt(v,u);
fa[rt]=u;
divi(rt);
}
}
inline void B_insert(heap &t,int k){
if(t.size()==0)t.push(k);
else if(t.size()==1)t.push(k),A.push(t.mx());
else{
int las=t.mx();t.push(k);
int now=t.mx();
if(las<now)A.pop(las),A.push(now);
}
}
inline void B_delet(heap &t,int k){
if(t.size()==1)t.pop(k);
else if(t.size()==2){
A.pop(t.mx());t.pop(k);
}
else{
int las=t.mx();t.pop(k);
int now=t.mx();
if(las>now)A.pop(las),A.push(now);
}
}
inline void C_insert(heap &t,heap &q,int k){
if(!t.size())t.push(k),B_insert(q,k);
else{
int las=t.top();t.push(k);
if(las<k)B_delet(q,las),B_insert(q,k);
}
}
inline void C_delet(heap &t,heap &q,int k){
if(t.size()==1)t.pop(k),B_delet(q,k);
else{
t.pop(k);
int now=t.top();
if(k>now)B_delet(q,k),B_insert(q,now);
}
}
inline void delet(int u,int v){
if(u==v){
if(B[u].size()==2)A.pop(B[u].mx());
B[u].pop(0);
}
if(!fa[u])return;
int f=fa[u],k=dist(f,v);
C_delet(C[u],B[f],k);
delet(f,v);
}
inline void add(int u,int v){
if(u==v){
B[u].push(0);
if(B[u].size()==2)A.push(B[u].mx());
}
if(!fa[u])return;
int f=fa[u],k=dist(f,v);
C_insert(C[u],B[f],k);
add(f,v);
}
char s;
signed main(){
// freopen("data.in","r",stdin);
n=in;
for(ri i=1;i<n;++i){
int u=in,v=in;
adde(u,v);
}
init();
maxn=n;rt=0;mx[0]=1e9;
getrt(1,0);
divi(rt);
for(ri i=1;i<=n;++i)add(i,i),col[i]=1;
m=in;
int all=n;
while(m--){
s=gc;
if(s=='G'){
if(all<2)cout<<all-1<<'\n';
else cout<<A.top()<<'\n';
gc;
}
if(s=='C'){
int k=in;
col[k]^=1;
if(col[k])add(k,k),++all;
else delet(k,k),--all;
}
}
return 0;
}