qtree4
https://zybuluo.com/ysner/note/1236834
题面
给出一棵边带权的节点数量为\(n\)的树,初始树上所有节点都是白色。有两种操作:
- 改变节点\(x\)的颜色,即白变黑,黑变白
- 询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为\(0\))。
\(n\leq10^5,q\leq2*10^5\)
解析
打这道题的过程中,\(get\)了许多新姿势。
点分治经典问题。每次分治时找到每棵子树深度最大的一个白点,用最大的两个统计一下即可。
找最大和次大自然需要堆,且每个点都需要开两个。
第一个堆插入这个重心管辖的一坨树所有白点到分治树上这个点父亲的距离。
第二个堆插入所有点分治树上孩子的堆顶,这样我们就可以对于每个分治重心,找到分属两棵子树的深度最大的两个白点,即这个点堆的最大和次大值。
修改就只要再点分树上从自己的重心往根走,然后维护一下那些堆。
注意这些堆要可删除(即可以指定删除其中一个元素)。
原理是每个堆里设一个删除堆和插入堆,插入元素就插入插入堆,删除元素就插入删除堆。如要取堆顶,就把两堆同时弹到堆顶不相等即可,取插入堆堆顶即可。
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
#define ll long long
#define re register
#define il inline
#define inf 1000000000
#define fp(i,a,b) for(re int i=a;i<=b;i++)
#define fq(i,a,b) for(re int i=a;i>=b;i--)
using namespace std;
const int N=5e5+100;
struct Edge{int to,nxt,w;}e[N<<1];
struct dui
{
priority_queue<int>s,t;int sz;
il void pop(re int x){t.push(x);--sz;}
il void push(re int x){s.push(x);++sz;}
il void pre(){while(t.size()&&s.top()==t.top()) s.pop(),t.pop();}
il int top(){pre();return sz?s.top():-inf;}
il int len()
{
if(sz<2) return 0;
re int x=top();pop(x);
re int y=top();push(x);
return max(x+y,0);
}
il void del(re int x,re int k){k?pop(x):push(x);}
}a[N],b[N],ans;
int n,h[N],cnt,Q,d[N],dis[N],f[N],sz[N],mx,mn,Sz[N],top[N],son[N],root,Size,F[N],w[N],tot,s[N],tim;
bool vis[N];
il void add(re int u,re int v,re int w){e[++cnt]=(Edge){v,h[u],w};h[u]=cnt;}
il ll gi()
{
re ll x=0,t=1;
re char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') t=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
return x*t;
}
il void dfs1(re int u,re int fa)
{
d[u]=d[fa]+1;f[u]=fa;sz[u]=1;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa) continue;
dis[v]=dis[u]+e[i].w;
dfs1(v,u);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v]) son[u]=v;
}
}
il void dfs2(re int u,re int up)
{
top[u]=up;
if(son[u]) dfs2(son[u],up);
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==f[u]||v==son[u]) continue;
dfs2(v,v);
}
}
il int lca(re int u,re int v)
{
while(top[u]^top[v])
{
if(d[top[u]]<d[top[v]]) swap(u,v);
u=f[top[u]];
}
return d[u]<d[v]?u:v;
}
il int Dis(re int u,re int v){return dis[u]+dis[v]-2*dis[lca(u,v)];}
il void Getrt(re int u,re int fa)
{
re int mx=0;Sz[u]=1;s[++tim]=u;
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(v==fa||vis[v]) continue;
Getrt(v,u);
Sz[u]+=Sz[v];
mx=max(mx,Sz[v]);
}
mx=max(mx,Size-Sz[u]);
if(mx<mn) mn=mx,root=u;
}
il int dfs(re int u,re int fa)
{
vis[u]=1;F[u]=fa;b[u].push(0);
if(F[u]) fp(i,1,tim) a[u].push(Dis(s[i],F[u]));
for(re int i=h[u];i+1;i=e[i].nxt)
{
re int v=e[i].to;
if(vis[v]) continue;
Size=Sz[v];mn=n;tim=0;
Getrt(v,u);
re int p=dfs(root,u);
b[u].push(a[p].top());
}
ans.push(b[u].len());
return u;
}
il void Modify(re int u,re int w)
{
re int l1=b[u].len(),l2,s1,s2;
b[u].del(0,w);l2=b[u].len();
if(l1^l2) ans.pop(l1),ans.push(l2);
for(re int i=u;F[i];i=F[i])
{
s1=a[i].top();
a[i].del(Dis(u,F[i]),w);
s2=a[i].top();
if(s1==s2) continue;
l1=b[F[i]].len();
if(s1!=-inf) b[F[i]].pop(s1);if(s2!=-inf) b[F[i]].push(s2);
l2=b[F[i]].len();
if(l1^l2) ans.pop(l1),ans.push(l2);
}
}
int main()
{
memset(h,-1,sizeof(h));
tot=n=gi();
fp(i,1,n-1)
{
re int u=gi(),v=gi(),w=gi();
add(u,v,w);add(v,u,w);
}
dfs1(1,0);dfs2(1,1);
Size=mn=n;Getrt(1,0);
dfs(root,0);
fp(i,1,n) w[i]=1;
Q=gi();
while(Q--)
{
re char op='0';while(op!='A'&&op!='C') op=getchar();
if(op=='A')
{
tot?printf("%d\n",tot==1?0:ans.top()):puts("They have disappeared.");
}
if(op=='C')
{
re int u=gi();tot+=(w[u]?-1:1);
Modify(u,w[u]);w[u]^=1;
}
}
return 0;
}