bzoj3999 [TJOI2015]旅游 树链剖分

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/82959298

Description


为了提高智商,ZJY准备去往一个新世界去旅游。这个世界的城市布局像一棵树。每两座城市之间只有一条路径可以互达。每座城市都有一种宝石,有一定的价格。ZJY为了赚取最高利益,她会选择从A城市买入再转手卖到B城市。由于ZJY买宝石时经常卖萌,因而凡是ZJY路过的城市,这座城市的宝石价格会上涨。让我们来算算ZJY旅游完之后能够赚取的最大利润。(如a城市宝石价格为v,则ZJY出售价格也为v)

1≤ N≤50000, 1≤Q ≤50000

Solution


一开始并没有甚么思路

注意到这个树上路径区间加的操作,我们可以上树链剖分
考虑怎么维护答案。我们在线段树上记录最大值、最小值、沿dfs序方向走的答案、逆dfs序方向走的答案
询问的时候把路径上连续的线段树区间合并起来。注意到一条路径(x,y)从x到lca和lca到y是反向的,因此我们拆成两条链来做就可以了

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)

using std:: max;
using std:: min;

const int INF=0x3f3f3f3f;
const int N=50005;

struct edge {int y,next;} e[N*2];
struct treeNode {int max,min,ans1,ans2;} rec[N<<2];

int bl[N],pos[N],dfn[N],tag[N<<2],a[N];
int size[N],fa[N],dep[N];
int ls[N],edCnt;

int read() {
	int x=0,v=1; char ch=getchar();
	for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
	for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
	return x*v;
}

void add_edge(int x,int y) {
	e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt;
	e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt;
}

void dfs1(int now) {
	size[now]=1;
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y==fa[now]) continue;
		fa[e[i].y]=now; dep[e[i].y]=dep[now]+1;
		dfs1(e[i].y); size[now]+=size[e[i].y];
	}
}

void dfs2(int now,int up) {
	bl[now]=up; dfn[pos[now]=++pos[0]]=now;
	int mx=0;
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y;
	}
	if (!mx) return ;
	dfs2(mx,up);
	for (int i=ls[now];i;i=e[i].next) {
		if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y);
	}
}

treeNode merge(treeNode a,treeNode b) {
	treeNode ret;
	ret.max=max(a.max,b.max);
	ret.min=min(a.min,b.min);
	ret.ans1=max(max(a.ans1,b.ans1),a.max-b.min);
	ret.ans2=max(max(a.ans2,b.ans2),b.max-a.min);
	return ret;
}

void push_up(int now) {
	rec[now]=merge(rec[now<<1],rec[now<<1|1]);
}

void push_down(int now) {
	if (!tag[now]) return ;
	int w=tag[now]; tag[now]=0;
	tag[now<<1]+=w; tag[now<<1|1]+=w;
	rec[now<<1].max+=w; rec[now<<1|1].max+=w;
	rec[now<<1].min+=w; rec[now<<1|1].min+=w;
}

void modify(int now,int tl,int tr,int l,int r,int v) {
	if (tl==l&&tr==r) {
		rec[now].max+=v; rec[now].min+=v;
		return (void) (tag[now]+=v);
	}
	push_down(now);
	int mid=(tl+tr)>>1;
	if (r<=mid) modify(now<<1,tl,mid,l,r,v);
	else if (l>mid) modify(now<<1|1,mid+1,tr,l,r,v);
	else {
		modify(now<<1,tl,mid,l,mid,v);
		modify(now<<1|1,mid+1,tr,mid+1,r,v);
	}
	push_up(now);
}

treeNode query(int now,int tl,int tr,int l,int r) {
	if (tl==l&&tr==r) return rec[now];
	int mid=(tl+tr)>>1;
	push_down(now);
	if (r<=mid) return query(now<<1,tl,mid,l,r);
	if (l>mid) return query(now<<1|1,mid+1,tr,l,r);
	treeNode qx=query(now<<1,tl,mid,l,mid),qy=query(now<<1|1,mid+1,tr,mid+1,r);
	return merge(qx,qy);
}

void change(int x,int y,int v) {
	for (;bl[x]!=bl[y];) {
		if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
		modify(1,1,pos[0],pos[bl[x]],pos[x],v);
		x=fa[bl[x]];
	}
	if (pos[x]>pos[y]) std:: swap(x,y);
	modify(1,1,pos[0],pos[x],pos[y],v);
}

int get_lca(int x,int y) {
	for (;bl[x]!=bl[y];) {
		if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y);
		x=fa[bl[x]];
	}
	return (dep[x]<dep[y])?x:y;
}

void solve(int x,int y) {
	int lca=get_lca(x,y);
	treeNode a,b; a=b=(treeNode) {-INF,INF,-INF,-INF};
	if (x!=lca) {
		for (;bl[x]!=bl[lca];) {
			a=merge(query(1,1,pos[0],pos[bl[x]],pos[x]),a);
			x=fa[bl[x]];
		}
		a=merge(query(1,1,pos[0],pos[lca],pos[x]),a);
	}
	if (y!=lca) {
		for (;bl[y]!=bl[lca];) {
			b=merge(query(1,1,pos[0],pos[bl[y]],pos[y]),b);
			y=fa[bl[y]];
		}
		b=merge(query(1,1,pos[0],pos[lca],pos[y]),b);
	}
	int ans=max(max(a.ans1,b.ans2),std:: max(b.max-a.min,0));
	printf("%d\n", ans);
}

void build(int now,int tl,int tr) {
	rec[now]=(treeNode) {-INF,INF,-INF,-INF};
	if (tl==tr) {
		rec[now].max=rec[now].min=a[dfn[tl]];
		return ;
	}
	int mid=(tl+tr)>>1;
	build(now<<1,tl,mid); build(now<<1|1,mid+1,tr);
	push_up(now);
}

int main(void) {
	int n=read();
	rep(i,1,n) a[i]=read();
	rep(i,2,n) add_edge(read(),read());
	dfs1(dep[1]=1); dfs2(1,1);
	build(1,1,n);
	// rep(i,1,n) modify(1,1,n,pos[i],pos[i],a[i]);
	for (int T=read();T--;) {
		int x=read(),y=read(),v=read();
		solve(x,y);
		change(x,y,v);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/82959298
今日推荐