题面
题意
给出一棵树,一开始所有点都是白点,每次一共有两种操作:
1.A,询问两端都是白点的路径的最大长度
2.C,改变某个点的颜色(白改黑或黑改白)。
做法
算法是树分治,边分和点分都可以。
边分相对要容易很多,因为它每次将树分为两个,统计方便,具体操作就是对于每条边的建两个支持删除某个元素的堆,分别维护这条边的左右两个端点不经过此边和其他边分中心的最大深度,然后再用一个总的支持删除的大根堆维护所有边的两个堆的top和的最大值。
在改变点的颜色时,只要沿着边分树(边分中心的构成的树)找到所有包含它的边,然后加入或删除元素即可。
支持删除的大根堆:维护两个大根堆a,b,加入元素时,加到a中,删除时,加入b中,每当要查询时,如果a,b两堆的top相等,全部pop,最后a.top()即为这整个堆的最大值。
最后要注意因为一个白点自己到自己也算一条路径,且边权可能为负,因而最后输出的答案要与0取较大值。
代码(边分)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#define P pair<int,int>
#define mp make_pair
#define fi first
#define se second
#define C ch=getchar()
#define INF 0x3f3f3f3f
#define N 200100
using namespace std;
int n,m,yun,bd,first[N],size[N],bb,so[N],dep[N],dz[N],top[N],fz[N],a[N],b[N],c[N],zx,deep[N];
bool vis[N],bla[N];
P sd[N],sb[N];
char ch;
struct Bn
{
int to,next,quan;
} bn[N<<1];
struct Pq
{
int s;
priority_queue<int>a,b;
void cle()
{
for(; !a.empty()&&!b.empty()&&a.top()==b.top(); a.pop(),b.pop());
}
void push(int u)
{
a.push(u);
s++;
}
void del(int u)
{
b.push(u);
s--;
}
int top()
{
cle();
return a.top();
}
bool empty()
{
return !s;
}
};
Pq pq[N][2],all;
vector<int>son[N],qn[N];
inline void add(int u,int v,int w)
{
bb++;
bn[bb].to=v;
bn[bb].next=first[u];
bn[bb].quan=w;
first[u]=bb;
}
inline void ad(int u,int v,int w)
{
add(u,v,w);
add(v,u,w);
}
inline int ask(int u)
{
if(pq[u][0].empty() || pq[u][1].empty()) return -INF;
return pq[u][0].top()+pq[u][1].top()+c[u];
}
void dfs(int now,int last)
{
int p,q;
for(p=first[now]; p!=-1; p=bn[p].next)
{
if(bn[p].to==last) continue;
son[now].push_back(bn[p].to);
qn[now].push_back(bn[p].quan);
dfs(bn[p].to,now);
}
}
inline void rb()
{
memset(first,-1,sizeof(first)),bb=1;
int i,j,p,q;
for(i=1; i<=n; i++)
{
if(son[i].size()<=2)
{
for(j=0; j<son[i].size(); j++)
{
ad(i,son[i][j],qn[i][j]);
}
}
else
{
p=++n,q=++n;
for(j=0; j<son[i].size(); j++)
{
if(j&1) son[p].push_back(son[i][j]),qn[p].push_back(qn[i][j]);
else son[q].push_back(son[i][j]),qn[q].push_back(qn[i][j]);
}
son[i].clear(),qn[i].clear();
son[i].push_back(p),son[i].push_back(q);
qn[i].push_back(0),qn[i].push_back(0);
ad(i,p,0),ad(i,q,0);
}
}
}
void gs(int now,int last)
{
int p,q;
size[now]=1;
for(p=first[now]; p!=-1; p=bn[p].next)
{
if(vis[p>>1] || bn[p].to==last) continue;
gs(bn[p].to,now);
size[now]+=size[bn[p].to];
}
}
P gr(int now,int last,int tot)
{
int p,q;
P res=mp(tot,0);
for(p=first[now]; p!=-1; p=bn[p].next)
{
if(vis[p>>1] || bn[p].to==last) continue;
res=min(res,gr(bn[p].to,now,tot));
res=min(res,mp((int)abs(tot-size[bn[p].to]*2),(int)(p>>1)));
}
return res;
}
int d1(int now,int last)
{
int p,q,res=1,mx=0,tmp;
for(p=first[now]; p!=-1; p=bn[p].next)
{
if(bn[p].to==last) continue;
fz[bn[p].to]=now;
dz[bn[p].to]=dz[now]+1;
dep[bn[p].to]=dep[now]+bn[p].quan;
tmp=d1(bn[p].to,now);
res+=tmp;
if(tmp>mx)
{
mx=tmp;
so[now]=bn[p].to;
}
}
return res;
}
void d2(int now,int last)
{
int p,q;
if(!so[now]) return;
else
{
top[so[now]]=top[now];
d2(so[now],now);
}
for(p=first[now]; p!=-1; p=bn[p].next)
{
if(bn[p].to==last || bn[p].to==so[now]) continue;
top[bn[p].to]=bn[p].to;
d2(bn[p].to,now);
}
}
inline int lca(int u,int v)
{
for(; top[u]!=top[v];)
{
if(dz[top[u]]<dz[top[v]]) swap(u,v);
u=fz[top[u]];
}
return dz[u]>dz[v]?v:u;
}
inline int len(int u,int v)
{
return dep[u]+dep[v]-2*dep[lca(u,v)];
}
void Dfs(int now,int last,bool bj)
{
int p,q;
if(now<=yun) pq[zx][bj].push(deep[now]),sd[now]=mp(zx,bj);
for(p=first[now]; p!=-1; p=bn[p].next)
{
if(bn[p].to==last || vis[p>>1]) continue;
deep[bn[p].to]=deep[now]+bn[p].quan;
Dfs(bn[p].to,now,bj);
}
}
void work(int now)
{
int p,q;
vis[now]=1;
zx=now;
deep[a[now]]=deep[b[now]]=0;
Dfs(a[now],-1,0);
Dfs(b[now],-1,1);
gs(a[now],-1);
p=gr(a[now],-1,size[a[now]]).se;
if(p)
{
sb[p]=mp(now,0);
work(p);
}
gs(b[now],-1);
p=gr(b[now],-1,size[b[now]]).se;
if(p)
{
sb[p]=mp(now,1);
work(p);
}
}
inline void xa(int u)
{
P tmp;
for(tmp=sd[u]; tmp.fi; tmp=sb[tmp.fi])
{
all.del(ask(tmp.fi));
pq[tmp.fi][tmp.se].push(len(u,tmp.se?b[tmp.fi]:a[tmp.fi]));
}
for(tmp=sd[u]; tmp.fi; tmp=sb[tmp.fi])
{
all.push(ask(tmp.fi));
}
}
inline void xd(int u)
{
P tmp;
for(tmp=sd[u]; tmp.fi; tmp=sb[tmp.fi])
{
all.del(ask(tmp.fi));
pq[tmp.fi][tmp.se].del(len(u,tmp.se?b[tmp.fi]:a[tmp.fi]));
}
for(tmp=sd[u]; tmp.fi; tmp=sb[tmp.fi])
{
all.push(ask(tmp.fi));
}
}
int main()
{
memset(first,-1,sizeof(first));
int i,j,p,q,o;
cin>>n;
yun=bd=n;
for(i=1; i<n; i++)
{
scanf("%d%d%d",&p,&q,&o);
ad(p,q,o);
}
for(i=1; i<=n; i++) son[i].clear();
dz[1]=top[1]=1;
dfs(1,-1);
rb();
d1(1,-1);
d2(1,-1);
for(i=2; i<=bb; i+=2)
{
a[i>>1]=bn[i].to;
b[i>>1]=bn[i+1].to;
c[i>>1]=bn[i].quan;
}
gs(1,-1);
p=gr(1,-1,size[1]).se;
work(p);
for(i=2; i<=bb; i+=2)
{
all.push(ask(i>>1));
}
cin>>m;
for(i=1; i<=m; i++)
{
for(C; ch!='A'&&ch!='C'; C);
if(ch=='A')
{
if(!bd) puts("They have disappeared.");
else if(bd==1) puts("0");
else printf("%d\n",max(0,all.top()));
}
else
{
scanf("%d",&o);
if(bla[o])
{
bd++;
bla[o]=0;
xa(o);
}
else
{
bd--;
bla[o]=1;
xd(o);
}
}
}
}
代码(点分)
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline","fast-math","unroll-loops","no-stack-protector")
#pragma GCC diagnostic error "-fwhole-program"
#pragma GCC diagnostic error "-fcse-skip-blocks"
#pragma GCC diagnostic error "-funsafe-loop-optimizations"
#pragma GCC diagnostic error "-std=c++14"
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
struct E
{
int to,nxt,d;
} e[200100];
int f1[100100],ne;
int ff[100100],n,sum,fx[100100],sz[100100];
int eu[200100],pos[200100],dpx[200100],dpx2[200100],st[200100][20],log2x[200100],lft[30];
int root;
bool fl[100100],vis[100100];
struct xxx
{
priority_queue<int> q1,q2;
int sz;
void insert(int x)
{
q1.push(x);
++sz;
}
void erase(int x)
{
q2.push(x);
--sz;
}
int size()
{
return sz;
}
void cl()
{
while(!q1.empty()&&!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
}
void pop()
{
cl();
q1.pop();
--sz;
}
int top()
{
cl();
return q1.top();
}
bool empty()
{
return sz==0;
}
};
xxx s[100100],s2[100100],s3;
//s[i]:i点管辖的连通块各个点到i点上层重心的距离
//s2[i]:i点的各个下层重心的s的最大值,**再加上一个0(i点到自身距离)
//s3:各个s2的前2大值之和
int getdis(int x,int y)
{
int l=pos[x],r=pos[y];
if(l>r) swap(l,r);
int k=log2x[r-l+1],t=dpx[pos[st[l][k]]]>dpx[pos[st[r-lft[k]+1][k]]]?st[r-lft[k]+1][k]:st[l][k];
return dpx2[pos[x]]+dpx2[pos[y]]-2*dpx2[pos[t]];
}
void getroot(int u,int fa)
{
sz[u]=1;
fx[u]=0;
for(int k=f1[u]; k; k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getroot(e[k].to,u);
sz[u]+=sz[e[k].to];
fx[u]=max(fx[u],sz[e[k].to]);
}
fx[u]=max(fx[u],sum-sz[u]);
if(fx[u]<fx[root]) root=u;
}
void getsz(int u,int fa)
{
sz[u]=1;
for(int k=f1[u]; k; k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
{
getsz(e[k].to,u);
sz[u]+=sz[e[k].to];
}
}
char tmp[20];
int getmax2(int p)
{
if(s2[p].size()<2) return -0x3f3f3f3f;
int t1=s2[p].top();
s2[p].pop();
int t2=s2[p].top();
s2[p].insert(t1);
return t1+t2;
}
void getdeep(int u,int fa)
{
s[root].insert(getdis(u,ff[root]));
for(int k=f1[u]; k; k=e[k].nxt)
if(!vis[e[k].to]&&e[k].to!=fa)
getdeep(e[k].to,u);
}
void solve(int u)
{
vis[u]=1;
s2[u].insert(0);
for(int k=f1[u]; k; k=e[k].nxt)
if(!vis[e[k].to])
{
getsz(e[k].to,0);
sum=sz[e[k].to];
root=0;
getroot(e[k].to,0);
ff[root]=u;
getdeep(root,0);
if(!s[root].empty()) s2[u].insert(s[root].top());
solve(root);
}
s3.insert(getmax2(u));
}
void dfs1(int u,int fa,int d,int d2)
{
eu[++eu[0]]=u;
pos[u]=eu[0];
dpx[eu[0]]=d;
dpx2[eu[0]]=d2;
for(int k=f1[u]; k; k=e[k].nxt)
if(e[k].to!=fa)
{
dfs1(e[k].to,u,d+1,d2+e[k].d);
eu[++eu[0]]=u;
dpx[eu[0]]=d;
dpx2[eu[0]]=d2;
}
}
void change(int u)
{
int now;
s3.erase(getmax2(u));
if(!fl[u]) s2[u].erase(0);
for(now=u; ff[now]; now=ff[now])
{
s3.erase(getmax2(ff[now]));
if(!s[now].empty()) s2[ff[now]].erase(s[now].top());
if(!fl[u]) s[now].erase(getdis(u,ff[now]));
}
fl[u]^=1;
if(!fl[u]) s2[u].insert(0);
s3.insert(getmax2(u));
for(now=u; ff[now]; now=ff[now])
{
if(!fl[u]) s[now].insert(getdis(u,ff[now]));
if(!s[now].empty()) s2[ff[now]].insert(s[now].top());
s3.insert(getmax2(ff[now]));
}
}
int num;
int main()
{
lft[0]=1;
fx[0]=0x3f3f3f3f;
int i,j,a,b,la=0,q,t,c;
for(i=1; i<=27; i++) lft[i]=(lft[i-1]<<1);
for(i=1; i<=200000; i++)
{
if(i>=lft[la+1]) ++la;
log2x[i]=la;
}
scanf("%d",&n);
for(i=1; i<n; i++)
{
scanf("%d%d%d",&a,&b,&c);
e[++ne].to=b;
e[ne].nxt=f1[a];
e[ne].d=c;
f1[a]=ne;
e[++ne].to=a;
e[ne].nxt=f1[b];
e[ne].d=c;
f1[b]=ne;
}
dfs1(1,0,0,0);
for(i=1; i<=eu[0]; i++) st[i][0]=eu[i];
for(j=1; (1<<j)<=eu[0]; j++)
for(i=1; i+lft[j]-1<=eu[0]; i++)
if(dpx[pos[st[i][j-1]]]>dpx[pos[st[i+lft[j-1]][j-1]]])
st[i][j]=st[i+lft[j-1]][j-1];
else
st[i][j]=st[i][j-1];
sum=n;
getroot(1,0);
solve(root);
scanf("%d",&q);
num=n;
while(q--)
{
scanf("%s",tmp);
if(tmp[0]=='A')
{
if(num==0) printf("They have disappeared.\n");
else if(num==1) printf("0\n");
else printf("%d\n",max(s3.top(),0));
}
else if(tmp[0]=='C')
{
scanf("%d",&t);
if(fl[t]) num++;
else num--;
change(t);
}
}
return 0;
}