首先,我们求出树的重链,然后对于每一条链,建一颗线段树
树大概长这样:
(其中用红边连起来的是一条条重链)
在线段树上,我们维护:
Opt(u):经过 u节点代表的链的其中一段 的两个白点间的最长路径长度
MaxL(u):u节点代表的链的左端点到最远的白点的距离
MaxR(u):u节点代表的链的右端点到最远的白点的距离
怎么维护呢?
我们再定义一些辅助变量方便描述:
D(i):节点i到最远的白点的距离
D2(i):节点i到次远的白点的距离
Dist(x,y):节点x,y之间的距离
Lc:线段树上左儿子
Rc:线段树上右儿子
当 l==r 即链只有一个节点时:
若u为黑色:
MaxL(u)=MaxR(u)=D(L)
Opt(u)=D(L)+D2(L)
若u为白色:
MaxL(u)=MaxR(u)=Max{D(L),0}
Opt(u)=Max{D(L)+D2(L),D(L)}
然后考虑如何push_up:
MaxL(u)=Max{MaxL(Lc),Dist(L,mid+1)+MaxL(Rc)}
MaxR(u)=Max{MaxR(Rc),Dist(mid,R)+MaxR(Lc)}
Opt(u)=Max{Opt(Lc),Opt(Rc),MaxR(Lc)+MaxL(Rc)+Dist(mid,mid+1)}
这样我们就维护好线段树啦,接下来考虑怎么在树上修改一个点的颜色:
假设我们要修改黄色点的颜色,那么我们肯定要修改被黄色笔框住的这条链
然后蓝色点肯定也被影响了,所以我们接下来修改被蓝色笔框住的这条链
再接下来绿色点也被影响力,所以我们修改被绿色笔框住的这条链
而下面已经没有点被影响了,修改结束
可见要修改一个点,我们只需要一层层链跳上去直到当前的链头无父节点为止
然后,我们还要考虑一下如何维护D(i)和D2(i) (节点到最远和次远白点的距离):
对此,我们对每个点维护一个大根堆,记录这个点到每个白点的距离
D(i)=s.top();
s.pop();
D2(i)=s.top();
s.push(D(i));
这样就可以求出D(i)和D2(i)啦
最后,在全局用个堆维护每条链的Opt,就可以直接查询了
这是Query on a tree IV的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=100005;
const int inf=1e9;
struct work{priority_queue <int> f,g;inline void ins(int v) { if(v != -inf) f.push(v); } inline void era(int v) { if(v != -inf) g.push(v); }inline int top() {while(1){if(f.empty()) return -inf;if(g.empty()) return f.top();if(f.top() == g.top()) f.pop(), g.pop();else return f.top();}}
}h[maxn], ans;
struct Edge{int u,v,w,next;
}edge[maxn<<1];
struct seg{int l,r,v,ls,rs;
}st[maxn<<2];
int wn,n,m,head[maxn],cnt,col[maxn],rt[maxn],onp;
int sz[maxn],fa[maxn],dep[maxn],son[maxn];
int tid[maxn],ord[maxn],ind,top[maxn],len[maxn];
inline int read() {int p=0,w=1; char ch=getchar();while(ch>'9'||ch<'0') {if(ch=='-') w = -1; ch=getchar();}while(ch>='0'&&ch<='9') p=p*10+ch-'0',ch=getchar();return p*w;
}
void add(int u,int v,int w){edge[cnt].u=u;edge[cnt].v=v;edge[cnt].w=w;edge[cnt].next=head[u];head[u]=cnt++;
}
#define dis(x) dep[ord[x]]
void push(int u,int l,int r){int ls=st[u].ls,rs=st[u].rs,mid=(l+r)>>1;st[u].l=max(st[ls].l,st[rs].l+dis(mid+1)-dis(l));//MaxL(u)=Max{MaxL(Lc),Dist(L,mid+1)+MaxL(Rc)}st[u].r=max(st[rs].r,st[ls].r+dis(r)-dis(mid));//MaxR(u)=Max{MaxR(Rc),Dist(mid,R)+MaxR(Lc)}st[u].v=max(max(st[ls].v,st[rs].v),st[ls].r+st[rs].l+dis(mid+1)-dis(mid));//Opt(u)=Max{Opt(Lc),Opt(Rc),MaxR(Lc)+MaxL(Rc)+Dist(mid,mid+1)}
}
void build(int &u,int l,int r){if(!u) u=++onp;if(l==r){int x=ord[l];for(int i=head[x];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==fa[x]||v==son[x]) continue;h[x].ins(st[rt[v]].l+dep[v]-dep[x]);}int d1=h[x].top(); h[x].era(d1); int d2=h[x].top(); h[x].ins(d1);st[u].l=st[u].r=max(d1,0); st[u].v=max(0,max(d1,d1+d2));//Opt(u)=Max{D(L)+D2(L),D(L)} 白色 return;}int mid =(l+r)>>1;build(st[u].ls,l,mid);build(st[u].rs,mid+1,r);push(u,l,r);
}
void update(int u,int l,int r,int v,int s){if(l==r){if(v==s){int d1=h[v].top();h[v].era(d1); int d2 = h[v].top(); h[v].ins(d1);if(col[v]) st[u].l=st[u].r=d1,st[u].v=d1+d2;//Opt=D(L)+D2(L) 黑色 else st[u].l=st[u].r=max(d1,0),st[u].v=max(0,max(d1,d1+d2));//Opt(u)=Max{D(L)+D2(L),D(L)} 白色 }else{h[v].ins(st[rt[s]].l+dep[s]-dep[v]);int d1 = h[v].top(); h[v].era(d1);int d2 = h[v].top(); h[v].ins(d1);if(col[v]) st[u].l=st[u].r=d1,st[u].v=d1+d2;//Opt=D(L)+D2(L) 黑色 else st[u].l=st[u].r=max(d1,0),st[u].v=max(0,max(d1,d1+d2));//Opt(u)=Max{D(L)+D2(L),D(L)} 白色 }return;}int mid=(l+r)>>1;if(tid[v]<=mid) update(st[u].ls,l,mid,v,s);else update(st[u].rs,mid+1,r,v,s);push(u,l,r);
}
void dfs1(int u){sz[u]=1;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;int w=edge[i].w;if(v==fa[u]) continue;fa[v]=u; dep[v]=dep[u]+w;dfs1(v);sz[u]+=sz[v];if(sz[v]>sz[son[u]]) son[u]=v;}
}
void dfs2(int u,int tp){tid[u]=++ind;top[u]=tp;ord[ind]=u;len[tp]++;if(!son[u]) return;dfs2(son[u],tp);for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(v==fa[u]||v==son[u]) continue;dfs2(v,v);}
}
int main(){ios::sync_with_stdio(false);memset(head,-1,sizeof(head));wn=n=read();int u,v,w;for(int i=1;i<n;i++){u=read();v=read();w=read();add(u,v,w);add(v,u,w);}dfs1(1);dfs2(1,1);ans.ins(0);for(int i=n;i;i--){int u=ord[i]; if(u!=top[u]) continue; build(rt[u],tid[u],tid[u]+len[u]-1); //每一条链建一线段树 ans.ins(st[rt[u]].v);}m=read();char ch;for(int i=1;i<=m;i++){ch=getchar();while(ch!='C'&&ch!='A') ch=getchar();if(ch=='C'){int x=read(); col[x]^= 1;if(col[x]==0) wn++; else wn --;for(int u=x,p=u;u;u=fa[u]){int tp=top[u];int p1=st[rt[tp]].v,d1=st[rt[tp]].l;if(fa[tp]) h[fa[tp]].era(st[rt[tp]].l+dep[tp]-dep[fa[tp]]);update(rt[tp],tid[tp],tid[tp]+len[tp]-1,u,p);int p2=st[rt[tp]].v,d2=st[rt[tp]].l;if(p1!=p2) ans.era(p1),ans.ins(p2);p=u=tp;}}else {if(wn==0) printf("They have disappeared.\n");else printf("%d\n", ans.top());}}return 0;
}
捉迷藏的代码只需要改一下输入输出,就不贴了