【清华集训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()<<"\n";
	}
	return 0;
}

posted @ 2019-03-20 17:57  hec0411  阅读(372)  评论(0编辑  收藏  举报