zoukankan      html  css  js  c++  java
  • 【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()<<'
    ';
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    CF #305(Div.2) D. Mike and Feet(数学推导)
    CF #305 (Div. 2) C. Mike and Frog(扩展欧几里得&&当然暴力is also no problem)
    2015百度之星资格赛.1004放盘子(数学推导)
    poj.1988.Cube Stacking(并查集)
    lightoj.1048.Conquering Keokradong(二分 + 贪心)
    CMD 命令汇总
    PLSQL 安装与配置 Oracle
    用 jQuery 实现简单倒计时功能
    C# 从服务器下载文件并保存到客户端
    用 NPOI 组件实现数据导出
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328352.html
Copyright © 2011-2022 走看看