由于边权为负,因此使用 DP 求答案。需维护每个点的最大和次大位置,单次修改 \(\mathcal O(n)\)。复杂度过劣。
考虑到所求为路径,考虑链分治。
设 \(D(i)\) 表示节点 \(i\) 轻子树的最大深度,\(D_2(i)\) 表示轻子树的次大深度。这两个值可以用堆维护。
考虑路径的形式必为由一个点的轻子树经重链到达另一个轻子树,对每条重链建立线段树维护答案,这是经典的。再用堆维护重链的答案。
考虑修改操作。注意到只有其在某个节点的轻子树中时才会改变答案,故直接顺着重链跳即可。
#include <cstdio>
#include <cctype>
#include <queue>
#include <algorithm>
using namespace std;
char buf[1<<14],*p1=buf,*p2=buf;
#define GetC() ((p1==p2)&&(p2=(p1=buf)+fread(buf,1,1<<14,stdin),p1==p2)?EOF:*p1++)
struct Ios{}io;
template <typename _tp>
Ios &operator >>(Ios &in,_tp &x){
x=0;int w=0;char c=GetC();
for(;!isdigit(c);w|=c=='-',c=GetC());
for(;isdigit(c);x=x*10+(c^'0'),c=GetC());
if(w) x=-x;
return in;
}
char gc(){
char c=GetC();
while(c==' '||c=='\n'||c=='\r') c=GetC();
return c;
}
const int N=100005,inf=5e8+5;
struct EDGE{int nxt,to,w;}e[N<<1];
int head[N],tot;
void add(int from,int to,int w){
e[++tot].nxt=head[from];
e[tot].to=to;
e[tot].w=w;
head[from]=tot;
}
int n,q,sum;
int sz[N],son[N],top[N],fa[N],dep[N];
void dfs1(int u,int f){
fa[u]=f;sz[u]=1;son[u]=-1;
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==f) continue ;
dep[v]=dep[u]+e[i].w;
dfs1(v,u);
sz[u]+=sz[v];
if(son[u]==-1||sz[v]>sz[son[u]]) son[u]=v;
}
}
int dfn[N],rev[N],len[N],ind;
void dfs2(int u,int topf){
dfn[u]=++ind;
rev[ind]=u;
top[u]=topf;
++len[top[u]];
if(son[u]!=-1) dfs2(son[u],topf);
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(v==fa[u]||v==son[u]) continue;
dfs2(v,v);
}
}
struct Heap{
priority_queue<int> q1,q2;
void push(int val){q1.push(val);}
void del(int val){q2.push(val);}
bool empty(){
while(!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
return q1.empty();
}
int top(){
while(!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
return q1.top();
}
void pop(){
while(!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
q1.pop();
while(!q2.empty()&&q1.top()==q2.top()) q1.pop(),q2.pop();
}
}ans,light[N];
int lmx[N<<1],rmx[N<<1],mx[N<<1],lc[N<<1],rc[N<<1];
int rt[N];
int cnt=0;
void push_up(int p,int l,int r){
int mid=(l+r)>>1;
lmx[p]=max(lmx[lc[p]],dep[rev[mid+1]]-dep[rev[l]]+lmx[rc[p]]);
rmx[p]=max(rmx[rc[p]],dep[rev[r]]-dep[rev[mid]]+rmx[lc[p]]);
mx[p]=max({mx[lc[p]],mx[rc[p]],rmx[lc[p]]+lmx[rc[p]]+dep[rev[mid+1]]-dep[rev[mid]]});
}
int col[N];
void build(int &p,int l,int r){
if(!p) p=++cnt;
if(l==r){
int u=rev[l];
int d1=light[u].top();light[u].pop();
int d2=light[u].top();light[u].push(d1);
lmx[p]=rmx[p]=max(0,d1);
mx[p]=max({0,d1,d1+d2});
return ;
}
int mid=(l+r)>>1;
build(lc[p],l,mid);
build(rc[p],mid+1,r);
push_up(p,l,r);
}
void modify(int p,int l,int r,int x){
if(l==r){
int u=rev[l];
int d1=light[u].top();light[u].pop();
int d2=light[u].top();light[u].push(d1);
if(col[u]){
lmx[p]=rmx[p]=max(0,d1);
mx[p]=max({0,d1,d1+d2});
}
else{
lmx[p]=rmx[p]=mx[p]=-inf;
if(d1!=-inf) lmx[p]=rmx[p]=d1;
if(d2!=-inf) mx[p]=d1+d2;
}
return ;
}
int mid=(l+r)>>1;
if(x<=mid) modify(lc[p],l,mid,x);
else modify(rc[p],mid+1,r,x);
push_up(p,l,r);
}
void update(int x){
if(col[x]) --sum;
else ++sum;
col[x]^=1;
while(x){
int u=top[x];
ans.del(mx[rt[u]]);
light[fa[u]].del(lmx[rt[u]]+dep[u]-dep[fa[u]]);
modify(rt[u],dfn[u],dfn[u]+len[u]-1,dfn[x]);
light[fa[u]].push(lmx[rt[u]]+dep[u]-dep[fa[u]]);
ans.push(mx[rt[u]]);
x=fa[top[x]];
}
}
int main(){
int n;io>>n;
for(int i=1;i<n;++i){
int u,v,w;io>>u>>v>>w;
add(u,v,w);add(v,u,w);
}
dfs1(1,0);
dfs2(1,1);
sum=n;
for(int i=1;i<=n;++i) col[i]=1,light[i].push(-inf),light[i].push(-inf);
for(int i=n;i;--i){
int u=rev[i];
if(u==top[u]){
build(rt[u],i,i+len[u]-1);
if(u!=1) light[fa[u]].push(lmx[rt[u]]+dep[u]-dep[fa[u]]);
ans.push(mx[rt[u]]);
}
}
int q;io>>q;
while(q--){
char opt=gc();
if(opt=='C'){
int x;io>>x;
update(x);
}
else{
if(sum) printf("%d\n",ans.top());
else puts("They have disappeared.");
}
}
return 0;
}
标签:q1,P4115,q2,int,top,Qtree4,pop,d1
From: https://www.cnblogs.com/pref-ctrl27/p/16947253.html