今天写了一晚上的动态点分治,一直写一直写,就是写不出来
无奈对着题解一直写一直调,超级痛苦
这动态点分治分治其实也不难理解,就是点分树还有比较暴力的一些操作
复杂度大概在nlog2n,但是写着就很恶心
最奇怪的是我对于&地址符号的引用开始是不以为意的
但是最后发现T了,无奈照着题解又看,发现原来这就是关键点
似乎调用&会少一层递归,复杂度就会更优秀?
其他的思路还是比较明了的
维护一个优先队列时
开一个优先队列存有的,一个存删去的,当重复的时候就直接去掉就可以了
我们一共维护两个优先队列,一个表示其分离子树中每个到它的最长链,一个表示其块内到父重心的最长链
然后稍微维护一下就可以了
代码如下
#include<bits/stdc++.h>
using namespace std;
int father[100005][20],to[200005],nxt[200005],head[100005];
int depth[100005],tot,root,sum,size[100005],vis[100005];
int maxa[100005],fa[100005],n,shu1,shu2,shu,cnt;
int color[100005],q;
char cha;
int read()
{
char c;
int x;
for(c=getchar();c!='-'&&(c>'9'||c<'0');c=getchar());
if(c=='-')
{
x=0;
for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return -x;
}
else
{
x=c-'0';
for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
return x;
}
}
struct heap
{
priority_queue <int> a,b;
void push(int x){a.push(x);}
void pop(int x){b.push(x);}
int top()
{
while(!b.empty()&&a.top()==b.top())
a.pop(),b.pop();
return a.top();
}
void pop()
{
while(!b.empty()&&a.top()==b.top())
a.pop(),b.pop();
a.pop();
}
int sectop()
{
int temp=top();pop();
int re=top();push(temp);
return re;
}
int size()
{
return a.size()-b.size();
}
}one[100005],two[100005],ans;
void insert(heap &x)
{
if(x.size()>=2)
ans.push(x.top()+x.sectop());//3
}
void erase(heap &x)
{
if(x.size()>=2)
ans.pop(x.top()+x.sectop());
}
void add(int x,int y)
{
to[++tot]=y;
nxt[tot]=head[x];
head[x]=tot;
}
void dfs(int x,int fa)
{
for(int i=1;i<=18;i++)
father[x][i]=father[father[x][i-1]][i-1];
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa) continue;
father[y][0]=x;
depth[y]=depth[x]+1;
dfs(y,x);
}
}
int lca(int x,int y)
{
if(depth[x]<depth[y])
swap(x,y);
int delta=depth[x]-depth[y];
for(int i=0;i<=18;i++)
if(delta>>i&1)
x=father[x][i];
if(x==y) return x;
for(int i=18;i>=0;i--)
{
if(father[x][i]!=father[y][i])
{
x=father[x][i];
y=father[y][i];
}
}
return father[x][0];
}
void findroot(int x,int fa)
{
size[x]=1;maxa[x]=0;
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(y==fa||vis[y]) continue;
findroot(y,x);
size[x]+=size[y];
maxa[x]=max(maxa[x],size[y]);
}
maxa[x]=max(maxa[x],sum-size[x]);
if(maxa[x]<maxa[root]) root=x;
}
int dis(int x,int y)
{
return depth[x]+depth[y]-2*depth[lca(x,y)];
}
void calc(int x,int fa,int now)
{
one[root].push(dis(x,now));//1
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(vis[y]||y==fa) continue;
calc(y,x,now);
}
}
void solve(int x,int faa)
{
fa[x]=faa;
vis[x]=1;
two[x].push(0);//2
calc(x,0,faa);
for(int i=head[x];i;i=nxt[i])
{
int y=to[i];
if(vis[y]) continue;
sum=size[y];
root=0;
findroot(y,x);
int now=root;
solve(root,x);
two[x].push(one[now].top());
}
insert(two[x]);
}
void turnon(int x)
{
erase(two[x]);
two[x].pop(0);
insert(two[x]);
for(int y=x;fa[y];y=fa[y])
{
erase(two[fa[y]]);
if(one[y].size()) two[fa[y]].pop(one[y].top());
one[y].pop(dis(x,fa[y]));
if(one[y].size()) two[fa[y]].push(one[y].top());
insert(two[fa[y]]);
}
}
void turnoff(int x)
{
erase(two[x]);
two[x].push(0);
insert(two[x]);
for(int y=x;fa[y];y=fa[y])
{
erase(two[fa[y]]);
if(one[y].size()) two[fa[y]].pop(one[y].top());
one[y].push(dis(x,fa[y]));
if(one[y].size()) two[fa[y]].push(one[y].top());
insert(two[fa[y]]);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n-1;i++)
{
shu1=read();
shu2=read();
add(shu1,shu2);
add(shu2,shu1);
}
root=0;
size[0]=n;
maxa[0]=n;
sum=n;
depth[1]=1;
dfs(1,0);
findroot(1,0);
solve(root,0);
cnt=n;
cin>>q;
for(int i=1;i<=q;i++)
{
scanf("\n%c",&cha);
if(cha=='G')
{
if(cnt<=1)
printf("%d\n",cnt-1);
else printf("%d\n",ans.top());
}
else
{
shu=read();
if(!color[shu])
{
color[shu]^=1;turnon(shu);cnt--;
}
else
{
color[shu]^=1;turnoff(shu);cnt++;
}
}
}
return 0;
}