【UOJ #268】【清华集训2016】数据交互(动态DP)

传送门

首先一个结论是所有相交的链一定满足其中一个的lcalca在另一个的lcalca

考虑对于每一条链
除了lcalca的点加上一个aa,lcalca加一个bb
那么一条路径的权值就是路径所有点的bb加上lcalca处的aa

考虑询问的是全局的答案
用一个可删堆存每个点作为lcalca的答案
那么就是从往下的链中选2个出来
先重链剖分
再对每一个点维护一个可删堆存所有轻儿子的往下最大权值valval
对于重链则是相当于是做一个类似最大子段和的东西
就是maxu,v(val[u]+val[v]+sumb(u,v)+a[u])\max_{u,v}(val[u]+val[v]+sum_b(u,v)+a[u])
注意到aa的区间加,实际上只会对一个点作为lcalca产生贡献
如果用类似线段树的最大子段和的做法,则只会影响rmxrmx
valval的变化也不改变sumsum

还要考虑由两个轻儿子拼起来的情况

具体实现可以看代码

#include<bits/stdc++.h>
using namespace std;
#define cs const
#define re register
#define pii pair<int,int>
#define fi first
#define se second
#define ll long long
#define pb push_back
cs int RLEN=1<<20|1;
inline char gc(){
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob)&&(ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob)?EOF:*ib++;
}
inline int read(){
	char ch=gc();
	int res=0;bool f=1;
	while(!isdigit(ch))f^=ch=='-',ch=gc();
	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
	return f?res:-res;
}
inline char readchar(){
	char ch=gc();
	while(isspace(ch))ch=gc();
	return ch;
}
template<class tp>inline void chemx(tp &a,tp b){a<b?a=b:0;}
template<class tp>inline void chemn(tp &a,tp b){a>b?a=b:0;}
cs int N=100005;
struct heap{
	priority_queue<ll>a,b;
	inline void push(ll x){a.push(x);}
	inline void erase(ll x){b.push(x);}
	inline ll top(){
		while(b.size()&&a.top()==b.top())
			a.pop(),b.pop();
		return a.top();
	}
	inline ll setop(){
		while(b.size()&&a.top()==b.top())
			a.pop(),b.pop();
		ll x=a.top();
		a.pop();
		if(!a.size())return a.push(x),0;
		while(b.size()&&a.top()==b.top())
			a.pop(),b.pop();
		if(!a.size())return a.push(x),0;
		ll y=a.top();a.push(x);
		return y;
	}
}ans,s[N];
struct node{
	ll lmx,rmx,s,ans;
	node(){lmx=rmx=s=ans=0;}
	friend inline node operator +(cs node &a,cs node &b){
		node c;
		c.s=a.s+b.s;
		c.lmx=max(a.lmx,a.s+b.lmx);
		c.rmx=max(b.rmx,a.rmx+b.s);
		c.ans=max(max(a.ans,b.ans),a.rmx+b.lmx);
		return c;
	}
};
struct opt{
	int u,v,w;
}pt[N];
vector<int> e[N];
int siz[N],fa[N],top[N],dep[N],son[N],ed[N],in[N],dfn;
int n,m;
void dfs1(int u){
	siz[u]=1;
	for(int &v:e[u]){
		if(v==fa[u])continue;
		fa[v]=u,dep[v]=dep[u]+1;
		dfs1(v),siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void dfs2(int u,int tp){
	top[u]=tp,ed[tp]=u,in[u]=++dfn;
	if(son[u])dfs2(son[u],tp);
	for(int &v:e[u]){
		if(v==fa[u]||v==son[u])continue;
		dfs2(v,v);
	}
}
namespace Seg{
	cs int N=::N<<2;
	node s[N];ll tag[N];
	#define lc (u<<1)
	#define rc ((u<<1)|1)
	#define mid ((l+r)>>1)
	inline void pushnow(int u,ll k){
		tag[u]+=k,s[u].ans+=k,s[u].rmx+=k;
	}
	inline void pushdown(int u){
		if(!tag[u])return;
		pushnow(lc,tag[u]);
		pushnow(rc,tag[u]);
		tag[u]=0;
	}
	inline void pushup(int u){
		s[u]=s[lc]+s[rc];
	}
	void update(int u,int l,int r,int st,int des,int k){
		if(st<=l&&r<=des)return pushnow(u,k);
		pushdown(u);
		if(st<=mid)update(lc,l,mid,st,des,k);
		if(mid<des)update(rc,mid+1,r,st,des,k);
		pushup(u);
	}
	void updatea(int u,int l,int r,int p,int k){
		if(l==r){s[u].lmx+=k,s[u].rmx+=k,s[u].ans+=k,s[u].s+=k;return;}
		pushdown(u);
		if(p<=mid)updatea(lc,l,mid,p,k);
		else updatea(rc,mid+1,r,p,k);
		pushup(u);
	}
	void updatep(int u,int l,int r,int p,ll k1,ll k2){
		if(l==r){
			s[u].lmx+=k1,s[u].rmx+=k1,s[u].ans+=k1+k2;
			return;
		}
		pushdown(u);
		if(p<=mid)updatep(lc,l,mid,p,k1,k2);
		else updatep(rc,mid+1,r,p,k1,k2);
		pushup(u);
	}
	node query(int u,int l,int r,int st,int des){
		if(st<=l&&r<=des)return s[u];
		pushdown(u);
		if(des<=mid)return query(lc,l,mid,st,des);
		if(mid<st)return query(rc,mid+1,r,st,des);
		return query(lc,l,mid,st,des)+query(rc,mid+1,r,st,des);
	}
	#undef lc
	#undef rc
	#undef mid
}
inline int pathupdate(int u,int v,int k){
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]])swap(u,v);
		Seg::update(1,1,n,in[top[u]],in[u],k);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v])swap(u,v);
	if(u!=v)Seg::update(1,1,n,in[v]+1,in[u],k);
	return v;
}
ll anc[N],lmx[N],prt[N],prs[N];
inline void pathquery(int u){
	while(0721){
		int tp=top[u],ff=fa[tp];
		node now=Seg::query(1,1,n,in[tp],in[ed[tp]]);
		ans.erase(anc[tp]);
		anc[tp]=now.ans;
		ans.push(anc[tp]);
		if(!ff)break;
		ll prmx=prt[ff],semx=prs[ff];
		s[ff].erase(lmx[tp]);
		lmx[tp]=now.lmx;
		s[ff].push(lmx[tp]);
		prt[ff]=s[ff].top(),prs[ff]=s[ff].setop();
		Seg::updatep(1,1,n,in[ff],prt[ff]-prmx,prs[ff]-semx);
		u=ff;
	}
}
signed main(){
	#ifdef Stargazer
	freopen("lx.cpp","r",stdin);
	#endif
	n=read(),m=read();
	for(int i=1;i<n;i++){
		int u=read(),v=read();
		e[u].pb(v),e[v].pb(u);
	}
	dfs1(1),dfs2(1,1);
	for(int i=1;i<=n;i++)s[i].push(0),ans.push(0);
	for(int i=1;i<=m;i++){
		char ch=readchar();
		int u,v,w;
		if(ch=='+'){
			u=read(),v=read(),w=read();
			pt[i].u=u,pt[i].v=v,pt[i].w=w;
		}
		else {
			int tt=read();
			u=pt[tt].u,v=pt[tt].v,w=-pt[tt].w;
		}
		int lca=pathupdate(u,v,w);//except lca
		Seg::updatea(1,1,n,in[lca],w);
		pathquery(u),pathquery(v);
		cout<<ans.top()<<'\n';
	}
	return 0;
}

posted @ 2019-12-17 18:54  Stargazer_cykoi  阅读(144)  评论(0编辑  收藏  举报