[UOJ#268]. 【清华集训2016】数据交互[动态dp+可删堆维护最长链]

题意

给出 \(n\) 个点的树,每个时刻可能出现一条路径 \(A_i\) 或者之前出现的某条路径 \(A_i\) 消失,每条路径有一个权值,求出在每个时刻过后能够找到的权值最大的路径(指所有和该路径有交的路径 \(A\) 的权值和) \(B\) 的权值是多少。
\(n\leq 10^5\)

分析

结论:两条树上路径有交,则一定有一条路径经过另一条路径的 \(lca\).

  • 根据上面的性质我们考虑用树形dp的方式求解。

  • 将一条路径的权值在每个点 \(x\) 关系分成两种:

    • \(a\) :路径的 \(lca\)\(x\)
    • \(b\) :路径的 \(lca\)\(x\) 的祖先;
  • 假设现在已经选定了一条路径 \(B\),那么该路径的权值就是途径所有点的 \(a\)\(lca\)\(b\) 之和 .

  • 考虑动态dp,因为树剖之后答案一定可以写成一段轻链+一段重链+一段轻链的形式。

  • 然后全局再用一个可删堆维护每条重链的答案即可。

  • 总时间复杂度为 \(O(nlog^2n)\)

注意可删堆取次大值时要两次检查堆顶是否要被删除

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].lst,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch))	{if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-48;ch=getchar();}
	return x*f;
}
template<typename T>inline bool Max(T &a,T b){return a<b?a=b,1:0;}
template<typename T>inline bool Min(T &a,T b){return b<a?a=b,1:0;}
const int N=1e5 + 7,Nd=N<<2;
int n,m,edc;
int head[N],x[N],y[N],w[N];
struct edge{
	int lst,to;
	edge(){}edge(int lst,int to):lst(lst),to(to){}
}e[N*2];
void Add(int a,int b){
	e[++edc]=edge(head[a],b),head[a]=edc;
	e[++edc]=edge(head[b],a),head[b]=edc;
}
// slpf
int son[N],zson[N],fa[N],dep[N],in[N],top[N],rev[N],down[N],tim;
void dfs1(int u){
	son[u]=1;
	go(u)if(v^fa[u]){
		fa[v]=u,dep[v]=dep[u]+1,dfs1(v);
		son[u]+=son[v];
		if(son[v]>son[zson[u]]) zson[u]=v;
	}
}
void dfs2(int u,int from){
	top[u]=from,in[u]=++tim,rev[tim]=u,down[u]=u;
	if(zson[u]) dfs2(zson[u],from),down[u]=down[zson[u]];
	go(u)if(v^fa[u]&&v^zson[u]) dfs2(v,v);
}
int Lca(int x,int y){
	for(;top[x]^top[y];y=fa[top[y]])
	if(dep[top[x]]>dep[top[y]]) swap(x,y);
	return dep[x]<dep[y]?x:y;
}
//sgt
#define Ls o<<1
#define Rs o<<1|1
struct data{
	LL l,r,s,mx;
	data(){}
	data operator +(const data &rhs)const{
		data res;
		res.l=max(l,s+rhs.l);
		res.r=max(rhs.r,rhs.s+r);
		res.s=s+rhs.s;
		res.mx=max(max(mx,rhs.mx),r+rhs.l);
		return res;
	}
}t[N<<2];
char s[10];
LL addv[Nd],g[Nd],se[Nd];
void st1(int o,LL v){
	t[o].r+=v,t[o].mx+=v;
	addv[o]+=v;
}
void pushup(int o){
	t[o]=t[Ls]+t[Rs];
}
void pushdown(int o){
	if(!addv[o]) return;
	st1(Ls,addv[o]);
	st1(Rs,addv[o]);
	addv[o]=0;
}
void ma(int p,int l,int r,int o,int opt,LL v){
	if(l==r){
		if(!opt){
			t[o].l+=v,t[o].r+=v,t[o].s+=v,t[o].mx+=v;
		}else if(opt==1){
			LL x=v-g[o];g[o]=v;
			t[o].l+=x,t[o].r+=x,t[o].mx+=x;
		}else{
			LL x=v-se[o];se[o]=v;
			t[o].mx+=x;
		}
		return;
	}
	pushdown(o);int mid=l+r>>1;
	if(p<=mid) ma(p,l,mid,Ls,opt,v);
	else ma(p,mid+1,r,Rs,opt,v);
	pushup(o);
}
void mb(int L,int R,int l,int r,int o,LL v){
	if(L>R) return;
	if(L<=l&&r<=R){
		st1(o,v);
		return;
	}
	pushdown(o);int mid=l+r>>1;
	if(L<=mid) mb(L,R,l,mid,Ls,v);
	if(R>mid)  mb(L,R,mid+1,r,Rs,v);
	pushup(o);
}
data query(int L,int R,int l,int r,int o){
	if(L<=l&&r<=R) return t[o];
	pushdown(o);int mid=l+r>>1;
	if(R<=mid) return query(L,R,l,mid,Ls);
	if(L>mid)  return query(L,R,mid+1,r,Rs);
	return query(L,R,l,mid,Ls)+query(L,R,mid+1,r,Rs);
}
struct Heap{
	priority_queue<LL>A,B;
	void push(LL x){A.push(x);}
	void pop(LL x){B.push(x);}
	LL top(){
		while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
		return A.empty()?0:A.top();
	}
	LL se(){
		while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
		if(A.empty()) return -1;
		LL x=A.top();A.pop();
		while(!B.empty()&&A.top()==B.top()) A.pop(),B.pop();
		if(B.empty()) {A.push(x);return -1;}
		LL y=A.top();A.push(x); 
		return y;
	}
}h[N],ans;
LL tans[N];
void upd(int u,int lca,LL v){
	int x=u;
	for(;u;u=fa[top[u]]){
		int gg=fa[top[u]];
		
		data res=query(in[top[u]],in[down[u]],1,n,1);
		h[gg].pop(res.l);
		if(tans[top[u]]) ans.pop(tans[top[u]]);
		
		if(u==x&&!lca) ma(in[u],1,n,1,0,v);
		else{
			if(lca) mb(max(in[top[u]],in[lca]+1),in[u],1,n,1,v);
			ma(in[u],1,n,1,1,h[u].top());
		}
		
		if(h[u].se()!=-1) ma(in[u],1,n,1,2,h[u].se());
		res=query(in[top[u]],in[down[u]],1,n,1);
		h[gg].push(res.l);
		ans.push(tans[top[u]]=res.mx);
	}
}
void pre(int u){
	go(u)if(v^fa[u]) pre(v);
	h[fa[top[u]]].push(0),ans.push(0);
}
int main(){
	n=gi(),m=gi();
	rep(i,1,n-1) Add(gi(),gi());
	dep[1]=1,dfs1(1),dfs2(1,1);
	pre(1);
	rep(i,1,m){
		scanf("%s",s);
		if(s[0]=='+'){
			x[i]=gi(),y[i]=gi(),w[i]=gi();
			int lca=Lca(x[i],y[i]);
			upd(lca,0,w[i]);
			upd(x[i],lca,w[i]);
			upd(y[i],lca,w[i]);
		}else{
			int t=gi(),lca=Lca(x[t],y[t]);
			upd(lca,0,-w[t]);
			upd(x[t],lca,-w[t]);
			upd(y[t],lca,-w[t]);
		}
		printf("%lld\n",ans.top());
	}
	return 0;
}
posted @ 2018-11-21 21:58  fwat  阅读(628)  评论(0编辑  收藏  举报