• 【清华集训2016】数据交互


    【清华集训2016】数据交互

    img
    img
    img

    比较神的(DDP)

    首先对于给出的一条链我们分两部分统计:(lca)以及其他部分。

    我们设两个变量(w_i,g_i)。一条路径的权值就是路径上所有点的(w)之和(+g_{lca})。所以我们将修改(w_{lca})的权值,修改其他点的(g)值。删除的时候就加一条相同的,权值相反的路径。

    具体细节就有多了。

    首先我们给每个点(v)开一个可删除堆表示(v)的虚子树中到(v)的最长链。再开一个全局的可删除堆记录每条链贡献的答案。我们发现,一条路径可以看成是重链上的(u,v)两点(其中(u)(lca)),以及这两点分别向虚子树伸出去的一条最长链(可以为空)。它的权值为这条链的(g)之和再加上(w_u)。当(u)等于(v)的时候,我们需要找最长链和次长链。

    我们发现这就是一个最大连续子段和。

    对于线段树上的一个节点,我们记录:

    (mx)表示答案。

    (lmx)表示从最左边代表的节点(深度最小)开始的最长链。

    (rmx)表示从最右边代表的节点(深度最大)开始的最长链。

    img

    还要记录(sum)表示区间内所有节点的(w)只和。

    一条重链的链顶的最长链就是这条重链对应的(lmx)

    修改的时候暴力将(lca)以上(log)条重链原来对其父亲贡献的最长链删除掉。更新过后将新的最长链贡献上去。

    更多细节就看代码吧:

    #include<bits/stdc++.h>
    #define ll long long
    #define N 100005
     
    using namespace std;
    inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
    
    int n,m;
    struct road {int to,next;}s[N<<1];
    int h[N],cnt;
    void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
    
    int fa[N],dep[N];
    int size[N],son[N];
    
    void dfs(int v) {
    	size[v]=1;
    	for(int i=h[v];i;i=s[i].next) {
    		int to=s[i].to;
    		if(to==fa[v]) continue ;
    		dep[to]=dep[v]+1;
    		fa[to]=v;
    		dfs(to);
    		if(size[son[v]]<size[to]) son[v]=to;
    		size[v]+=size[to];
    	}
    }
    
    int dfn[N],bot[N],top[N],id;
    int lst[N];
    void dfs2(int v,int tp) {
    	dfn[v]=++id;
    	lst[id]=v;
    	top[v]=tp;
    	bot[v]=v;
    	if(son[v]) {
    		dfs2(son[v],tp);
    		bot[v]=bot[son[v]];
    	}
    	for(int i=h[v];i;i=s[i].next) {
    		int to=s[i].to;
    		if(to==fa[v]||to==son[v]) continue ;
    		dfs2(to,to);
    	}
    }
    
    struct tree {
    	int l,r;
    	ll lmx,rmx;
    	ll mx,tag;
    	ll sum;
    	tree() {l=r=lmx=rmx=mx=tag=sum=0;}
    }tr[N<<2];
    
    struct Heap {
    	priority_queue<ll>add,del;
    	void Pop() {
    		while(del.size()&&add.top()==del.top()) {
    			add.pop();
    			del.pop();
    		}
    	}
    	void Push(ll x) {
    		Pop();
    		add.push(x);
    	}
    	void Del(ll x) {
    		del.push(x);
    	}
    	ll Top() {
    		Pop();
    		return add.top();
    	}
    	ll Sec() {
    		ll x=Top();
    		Del(x);
    		ll y=Top();
    		Push(x);
    		return y;
    	}
    }Ans,F[N];
    
    tree operator +(const tree &a,const tree &b) {
    	tree tem;
    	tem.l=a.l,tem.r=b.r;
    	tem.mx=max(a.rmx+b.lmx,max(a.mx,b.mx));
    	tem.lmx=max(a.lmx,a.sum+b.lmx);
    	tem.rmx=max(b.rmx,a.rmx+b.sum);
    	tem.sum=a.sum+b.sum;
    	return tem;
    }
    
    // sum 单点
    //tag 链 
    void Update(int v,int p) {
    	int u=lst[p];
    	ll fir=F[u].Top(),sec=F[u].Sec();
    	tr[v].lmx=tr[v].sum+fir;
    	tr[v].rmx=tr[v].tag+tr[v].sum+fir;
    	tr[v].mx=tr[v].tag+tr[v].sum+fir+sec;
    }
    
    void build(int v,int l,int r) {
    	tr[v].l=l,tr[v].r=r;
    	if(l==r) {
    		Update(v,l);
    		return ;
    	}
    	int mid=l+r>>1;
    	build(v<<1,l,mid),build(v<<1|1,mid+1,r);
    	tr[v]=tr[v<<1]+tr[v<<1|1];
    }
    
    void Set(int v,ll f) {
    	tr[v].mx+=f;
    	tr[v].tag+=f;
    //	tr[v].lmx+=f;
    	tr[v].rmx+=f;
    }
    
    void down(int v) {
    	if(tr[v].tag) {
    		Set(v<<1,tr[v].tag),Set(v<<1|1,tr[v].tag);
    		tr[v].tag=0;
    	}
    }
    
    void add_mx(int v,int l,int r,ll f) {//修改给出的整条链 
    	if(tr[v].l>r||tr[v].r<l) return ;
    	if(l<=tr[v].l&&tr[v].r<=r) {
    		Set(v,f);
    		return ;
    	}
    	down(v);
    	add_mx(v<<1,l,r,f),add_mx(v<<1|1,l,r,f);
    	tr[v]=tr[v<<1]+tr[v<<1|1];
    }
    
    void add_sum(int v,int p,int f) {//修改lca 
    	if(tr[v].l>p||tr[v].r<p) return ;
    	tr[v].sum+=f;
    	if(tr[v].l==tr[v].r) {
    		tr[v].lmx+=f;
    		tr[v].rmx+=f;
    		tr[v].mx+=f;
    		return ;
    	}
    	down(v);
    	add_sum(v<<1,p,f),add_sum(v<<1|1,p,f);
    	tr[v]=tr[v<<1]+tr[v<<1|1];
    }
    
    void update(int v,int p) {
    	if(tr[v].l>p||tr[v].r<p) return ;
    	if(tr[v].l==tr[v].r) {
    		Update(v,p);
    		return ;
    	}
    	down(v);
    	update(v<<1,p),update(v<<1|1,p);
    	tr[v]=tr[v<<1]+tr[v<<1|1];
    }
    
    tree query(int v,int l,int r) {
    	if(l<=tr[v].l&&tr[v].r<=r) return tr[v];
    	down(v);
    	int mid=tr[v].l+tr[v].r>>1;
    	if(r<=mid) return query(v<<1,l,r);
    	else if(l>mid) return query(v<<1|1,l,r);
    	else return query(v<<1,l,r)+query(v<<1|1,l,r);
    }
    
    int lca(int a,int b) {
    	while(top[a]!=top[b]) {
    		if(dep[top[a]]<dep[top[b]]) swap(a,b);
    		a=fa[top[a]];
    	}
    	return dep[a]<dep[b]?a:b;
    }
    
    void Modify_chain(int a,int b,int f) {
    	while(top[a]!=top[b]) {
    		if(dep[top[a]]<dep[top[b]]) swap(a,b);
    		add_mx(1,dfn[top[a]],dfn[a],f);
    		a=fa[top[a]];
    	}
    	if(dep[a]>dep[b]) swap(a,b);
    	add_mx(1,dfn[a],dfn[b],f);
    }
    
    void Del(int a,int b) {
    	static tree tem;
    	while(top[a]!=top[b]) {
    		if(dep[top[a]]<dep[top[b]]) swap(a,b);
    		tem=query(1,dfn[top[a]],dfn[bot[a]]);
    		Ans.Del(tem.mx);
    		a=fa[top[a]];
    	}
    	tem=query(1,dfn[top[a]],dfn[bot[a]]);
    	Ans.Del(tem.mx);	
    }
    
    void ADD(int a,int b) {
    	static tree tem;
    	while(top[a]!=top[b]) {
    		if(dep[top[a]]<dep[top[b]]) swap(a,b);
    		tem=query(1,dfn[top[a]],dfn[bot[a]]);
    		Ans.Push(tem.mx);
    		a=fa[top[a]];
    	}
    	tem=query(1,dfn[top[a]],dfn[bot[a]]);
    	Ans.Push(tem.mx);
    }
    
    void Modify(int a,int b,int w) {
    	int f=lca(a,b);
    	tree tem;
    	for(int i=top[f];i;i=top[fa[i]]) {
    		tem=query(1,dfn[i],dfn[bot[i]]);
    		if(fa[i]) F[fa[i]].Del(tem.lmx);
    		if(i!=top[f]) {
    			Ans.Del(tem.mx);
    		}
    	}
    	
    	Del(a,b);
    	add_sum(1,dfn[f],w);
    	Modify_chain(a,b,w);
    	Modify_chain(f,f,-w);
    	ADD(a,b);
    	for(int i=top[f];i;i=top[fa[i]]) {
    		tem=query(1,dfn[i],dfn[bot[i]]);
    		if(fa[i]) {
    			F[fa[i]].Push(tem.lmx);
    			update(1,dfn[fa[i]]);
    		}
    		if(i!=top[f]) Ans.Push(tem.mx);
    	}
    }
    
    struct edge {int x,y,w;}e[N];
    void out(int v) {
    	int x=top[v];
    	for(int i=dfn[x];;i++) {
    		cout<<lst[i]<<" ";
    		if(i==dfn[v]) return ;
    	}
    }
    
    int main() {
    	n=Get(),m=Get();
    	int a,b;
    	for(int i=1;i<n;i++) {
    		a=Get(),b=Get();
    		add(a,b),add(b,a);
    	}
    	dfs(1);
    	dfs2(1,1);
    	for(int i=1;i<=n;i++) F[i].Push(0),F[i].Push(0);
    	build(1,1,n);
    	for(int i=1;i<=n;i++) if(i==top[i]) Ans.Push(0);
    	char op;
    	for(int i=1;i<=m;i++) {
    		while(op=getchar(),op!='+'&&op!='-');
    		if(op=='+') {
    			e[i].x=Get(),e[i].y=Get(),e[i].w=Get();
    			Modify(e[i].x,e[i].y,e[i].w);
    		} else {
    			int id=Get();
    			Modify(e[id].x,e[id].y,-e[id].w);
    		}
    		cout<<Ans.Top()<<"
    ";
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    分享memcache和memcached安装过程(转)
    ios画图总结
    mac os下通过命令行的方式编译c++代码并在xcode里引用
    ubuntu访问windows共享文件夹
    为iphone 及iphone simulator编译boost库
    ubuntu 11.10 x64 安装oracle 11gR2时碰到的问题及解决方法
    模拟器与真机下ffmpeg的编译方法(总结版)
    ios 在View里绘图
    memcached1.4.4在ubuntu下编译的注意事项
    Google Code 服务试用
  • 原文地址:https://www.cnblogs.com/hchhch233/p/10566528.html
Copyright © 2020-2023  润新知