【BZOJ3999】【TJOI2015】旅游 树剖

题目大意

  给你一棵树,有\(n\)个点。有\(q\)个操作,每次要你从\(x\)\(y\)的路径上选两个点,使得距离\(x\)比较远的点的点权\(-\)距离\(x\)比较近的点的点权最大,然后把这条路径上所有点的点权\(+v\)

  \(n,q\leq 50000\)

题解

  这种题没什么意思,直接树剖就好了。

  线段树上每个点记录最大值,最小值,从左往右走和从右往左走的最大收益。

  时间复杂度:\(O(n+q\log^2 n)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
#include<cmath>
#include<functional>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
void sort(int &a,int &b)
{
	if(a>b)
		swap(a,b);
}
void open(const char *s)
{
#ifndef ONLINE_JUDGE
	char str[100];
	sprintf(str,"%s.in",s);
	freopen(str,"r",stdin);
	sprintf(str,"%s.out",s);
	freopen(str,"w",stdout);
#endif
}
int rd()
{
	int s=0,c;
	while((c=getchar())<'0'||c>'9');
	do
	{
		s=s*10+c-'0';
	}
	while((c=getchar())>='0'&&c<='9');
	return s;
}
int upmin(int &a,int b)
{
	if(b<a)
	{
		a=b;
		return 1;
	}
	return 0;
}
int upmax(int &a,int b)
{
	if(b>a)
	{
		a=b;
		return 1;
	}
	return 0;
}
struct pp
{
	ll ma,mi;
	ll s1,s2;
	pp()
	{
		ma=mi=s1=s2=0;
	}
};
pp merge(pp a,pp b)
{
	pp c;
	c.s1=max(b.ma-a.mi,max(a.s1,b.s1));
	c.s2=max(a.ma-b.mi,max(a.s2,b.s2));
	c.ma=max(a.ma,b.ma);
	c.mi=min(a.mi,b.mi);
	return c;
}
pp rev(pp a)
{
	swap(a.s1,a.s2);
	return a;
}
int c[100010];
namespace seg
{
	struct tree
	{
		int ls,rs;
		int l,r;
		ll t;
		pp s;
	};
	tree a[100010];
	int cnt;
	void build(int &p,int l,int r)
	{
		p=++cnt;
		a[p].l=l;
		a[p].r=r;
		if(l==r)
		{
			a[p].s.ma=a[p].s.mi=c[l];
			return;
		}
		int mid=(l+r)>>1;
		build(a[p].ls,l,mid);
		build(a[p].rs,mid+1,r);
		a[p].s=merge(a[a[p].ls].s,a[a[p].rs].s);
	}
	void add(int p,ll v)
	{
		a[p].s.ma+=v;
		a[p].s.mi+=v;
		a[p].t+=v;
	}
	void push(int p)
	{
		if(a[p].t&&a[p].ls!=a[p].r)
		{
			add(a[p].ls,a[p].t);
			add(a[p].rs,a[p].t);
			a[p].t=0;
		}
	}
	void add(int p,int l,int r,int v)
	{
		if(l<=a[p].l&&r>=a[p].r)
		{
			add(p,v);
			return;
		}
		push(p);
		int mid=(a[p].l+a[p].r)>>1;
		if(l<=mid)
			add(a[p].ls,l,r,v);
		if(r>mid)
			add(a[p].rs,l,r,v);
		a[p].s=merge(a[a[p].ls].s,a[a[p].rs].s);
	}
	pp query(int p,int l,int r)
	{
		if(l<=a[p].l&&r>=a[p].r)
			return a[p].s;
		push(p);
		int mid=(a[p].l+a[p].r)>>1;
		if(r<=mid)
			return query(a[p].ls,l,r);
		if(l>mid)
			return query(a[p].rs,l,r);
		return merge(query(a[p].ls,l,r),query(a[p].rs,l,r));
	}
}
struct graph
{
	int v[100010];
	int t[100010];
	int h[50010];
	int n;
	graph()
	{
		n=0;
	}
	void add(int x,int y)
	{
		n++;
		v[n]=y;
		t[n]=h[x];
		h[x]=n;
	}
};
graph g;
struct p
{
	int f,w,t,d,ms,s;
};
p a[100010];
int wcnt;
void dfs1(int x,int fa,int dep)
{
	a[x].f=fa;
	a[x].d=dep;
	a[x].s=1;
	int ms=0;
	int i;
	for(i=g.h[x];i;i=g.t[i])
		if(g.v[i]!=fa)
		{
			dfs1(g.v[i],x,dep+1);
			if(a[g.v[i]].s>ms)
			{
				ms=a[g.v[i]].s;
				a[x].ms=g.v[i];
			}
			a[x].s+=a[g.v[i]].s;
		}
}
void dfs2(int x,int top)
{
	a[x].w=++wcnt;
	a[x].t=top;
	if(!a[x].ms)
		return;
	dfs2(a[x].ms,top);
	int i;
	for(i=g.h[x];i;i=g.t[i])
		if(g.v[i]!=a[x].f&&g.v[i]!=a[x].ms)
			dfs2(g.v[i],g.v[i]);
}
int prize[100010];
int rt;
ll query(int x,int y,int z)
{
	pp s1,s2;
	s1.ma=s1.mi=0x7fffffff;
	s2.ma=s2.mi=-0x7fffffff;
	while(a[x].t!=a[y].t)
		if(a[a[x].t].d>a[a[y].t].d)
		{
			s1=merge(s1,rev(seg::query(rt,a[a[x].t].w,a[x].w)));
			seg::add(rt,a[a[x].t].w,a[x].w,z);
			x=a[a[x].t].f;
		}
		else
		{
			s2=merge(seg::query(rt,a[a[y].t].w,a[y].w),s2);
			seg::add(rt,a[a[y].t].w,a[y].w,z);
			y=a[a[y].t].f;
		}
	if(a[x].w<a[y].w)
	{
		s2=merge(seg::query(rt,a[x].w,a[y].w),s2);
		seg::add(rt,a[x].w,a[y].w,z);
	}
	else
	{
		s1=merge(s1,rev(seg::query(rt,a[y].w,a[x].w)));
		seg::add(rt,a[y].w,a[x].w,z);
	}
	s1=merge(s1,s2);
	return s1.s1;
}
int main()
{
	open("bzoj3999");
	int n,q;
	scanf("%d",&n);
	int i,x,y,z;
	for(i=1;i<=n;i++)
		scanf("%d",&prize[i]);
	for(i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		g.add(x,y);
		g.add(y,x);
	}
	dfs1(1,0,1);
	dfs2(1,1);
	for(i=1;i<=n;i++)
		c[a[i].w]=prize[i];
	seg::build(rt,1,n);
	scanf("%d",&q);
	for(i=1;i<=q;i++)
	{
		scanf("%d%d%d",&x,&y,&z);
		ll ans=query(x,y,z);
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2018-03-06 11:31  ywwyww  阅读(162)  评论(1编辑  收藏  举报