P4115 Qtree4

\(\mathcal Link\)

由于边权为负,因此使用 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;
}
posted @ 2022-12-04 16:46  pref_ctrl27  阅读(22)  评论(0编辑  收藏  举报