HDU 5022 Yaoge’s maximum profit(树链剖分+区间合并+方向)

Yaoge’s maximum profit

这基本上是一道金银分界线的题

题目大意:

给一棵树,给点权,然后查询从节点 x x x y y y,求最大值减最小值的 m a x max max(注意: x x x y y y是有方向的)。

首先不得不说,学弟nb

首先考虑方向

在这里插入图片描述

分为向上,和向下,即从 x x x L C A LCA LCA(上升),从 L C A LCA LCA y y y(下降)

维护每个区间的左边减右边的 m a x max max,以及右边减左边的 m a x max max,维护方法就是区间和并,因为区间修改对差没有影响,因此 p u s h d o w n pushdown pushdown照旧,但 p u s h u p pushup pushup要写成区间合并

注意在上升的时候,要右减左,下降的时候要左减右( q c h a i n qchain qchain的时候不能交换 x x x y y y),直接记录下来,然后进行一个合并操作即可

合并操作如下:

tree merge(tree p1,tree p2)
{
	
	tree p;
	
	p.sum[0]=max(p1.sum[0],p2.sum[0]);
	p.sum[0]=max(p2.ma-p1.mi,p.sum[0]);
	p.sum[0]=max(p.sum[0],(int)0);
	
	p.sum[1]=max(p1.sum[1],p2.sum[1]);
	p.sum[1]=max(p1.ma-p2.mi,p.sum[1]);
	p.sum[1]=max(p.sum[1],(int)0);
	
	p.ma=max(p1.ma,p2.ma);
	p.mi=min(p1.mi,p2.mi); 
	return p;
}

总代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
#define inf 0x7fffffff
#define ll long long
#define int long long
//#define double long double
#define re register int
#define void inline void
#define eps 1e-8
//#define mod 1e9+7
#define ls(p) p<<1
#define rs(p) p<<1|1
#define pi acos(-1.0)
#define pb push_back
#define P pair < int , int >
#define mk make_pair
using namespace std;
const int mod=998244353;
const int M=1e9;
const int N=2e5+5;//?????????? 4e8
struct node
{
	int ver,next;
}t[N];
struct tree
{
	int ma,mi,sum[2],add;
}e[N];
int a[N],w[N],dfn[N],tot,head[N];
int n,q;
int sz[N],son[N],top[N],fa[N],d[N];
int num;
void init()
{
	for(re i=0;i<=n+1;i++)
	{
		head[i]=w[i]=a[i]=dfn[i]=sz[i]=son[i]=top[i]=0;
		fa[i]=d[i]=0;
	}
	tot=num=0;
}
void add(int x,int y)
{
	t[++tot].ver=y;
	t[tot].next=head[x];
	head[x]=tot;
}
void addedge(int x,int y)
{
	add(x,y);add(y,x);
}
void dfs1(int x,int pre)
{
	int ma=-1;
	sz[x]=1;d[x]=d[pre]+1;fa[x]=pre;
	for(re i=head[x];i;i=t[i].next)
	{
		int y=t[i].ver;
		if(y==pre)  continue;
		dfs1(y,x);
		if(ma<sz[y])  ma=sz[y],son[x]=y;
		sz[x]+=sz[y]; 
	}
}
void dfs2(int x,int pre)
{
	dfn[x]=++num;
	top[x]=pre;
	w[num]=a[x];
	if(!son[x])  return;
	dfs2(son[x],pre);
	for(re i=head[x];i;i=t[i].next)
	{
		int y=t[i].ver;
		if(son[x]==y||fa[x]==y)  continue;
		dfs2(y,y);
	}
}
void push(int p)
{
	e[p].sum[0]=max(e[ls(p)].sum[0],e[rs(p)].sum[0]);
	e[p].sum[0]=max(e[rs(p)].ma-e[ls(p)].mi,e[p].sum[0]);
	e[p].sum[0]=max(e[p].sum[0],(int)0);
	
	e[p].sum[1]=max(e[ls(p)].sum[1],e[rs(p)].sum[1]);
	e[p].sum[1]=max(e[ls(p)].ma-e[rs(p)].mi,e[p].sum[1]);
	e[p].sum[1]=max(e[p].sum[1],(int)0);
	
	e[p].ma=max(e[ls(p)].ma,e[rs(p)].ma);
	e[p].mi=min(e[ls(p)].mi,e[rs(p)].mi); 
}
tree merge(tree p1,tree p2)
{
	
	tree p;
	
	p.sum[0]=max(p1.sum[0],p2.sum[0]);
	p.sum[0]=max(p2.ma-p1.mi,p.sum[0]);
	p.sum[0]=max(p.sum[0],(int)0);
	
	p.sum[1]=max(p1.sum[1],p2.sum[1]);
	p.sum[1]=max(p1.ma-p2.mi,p.sum[1]);
	p.sum[1]=max(p.sum[1],(int)0);
	
	p.ma=max(p1.ma,p2.ma);
	p.mi=min(p1.mi,p2.mi); 
	return p;
}
void bulid(int p,int l,int r)
{
	e[p].add=e[p].mi=e[p].ma=0;
	for(re i=0;i<=1;i++)  e[p].sum[i]=0;
	if(l==r)
	{
		e[p].ma=e[p].mi=w[l];
		return;
	}
	int mid=(l+r)>>1;
	bulid(ls(p),l,mid);bulid(rs(p),mid+1,r);
	push(p);
}
void spread(int p)
{
	if(!e[p].add)  return;
	e[ls(p)].ma+=e[p].add;
	e[ls(p)].mi+=e[p].add;
	
	e[rs(p)].ma+=e[p].add;
	e[rs(p)].mi+=e[p].add;
	
	e[ls(p)].add+=e[p].add;
	e[rs(p)].add+=e[p].add;
	
	e[p].add=0;
}
void change(int p,int L,int R,int l,int r,int v)
{
	if(L<=l&&r<=R)
	{
		e[p].ma+=v;
		e[p].mi+=v;
		e[p].add+=v;
		return;
	}
	spread(p); 
	int mid=(l+r)>>1;
	if(L<=mid)  change(ls(p),L,R,l,mid,v);
	if(mid<R)  change(rs(p),L,R,mid+1,r,v);
	push(p);
}
tree ask(int p,int L,int R,int l,int r)
{
	if(L<=l&&r<=R)  return e[p];
	spread(p);
	int mid=(l+r)>>1;
	if(R<=mid)  return ask(ls(p),L,R,l,mid);
	else if(L>mid)  return ask(rs(p),L,R,mid+1,r);
	else  return merge(ask(ls(p),L,R,l,mid),ask(rs(p),L,R,mid+1,r));
}
tree cnt[N],instack[N];
void print(tree p)
{
//	puts("132f1a");
//	printf("%lld %lld %lld %lld %lld\n",p.ma,p.mi,p.sum[0],p.sum[1],p.add);
}
int qchain(int x,int y,int z)
{
	tree ans;
	int t=0,top1=0;
	while(top[x]!=top[y])
	{
		
//		cout<<"xzfcz"<<endl;
		if(d[top[x]]<d[top[y]])
		{
//			cout<<dfn[top[y]]<<" "<<dfn[y]<<endl;
			ans=ask(1,dfn[top[y]],dfn[y],1,n);
			print(ans);
			change(1,dfn[top[y]],dfn[y],1,n,z);
			y=fa[top[y]];
			instack[++top1]=ans;
		}
		else
		{
//			cout<<dfn[top[x]]<<" "<<dfn[x]<<endl;
			ans=ask(1,dfn[top[x]],dfn[x],1,n);
			print(ans);
			change(1,dfn[top[x]],dfn[x],1,n,z);
			x=fa[top[x]];
			cnt[++t]=ans;
		}
	}
	if(d[x]<d[y])
	{
		ans=ask(1,dfn[x],dfn[y],1,n);
		change(1,dfn[x],dfn[y],1,n,z);
		instack[++top1]=ans;
		print(ans);
	}
	else
	{
		ans=ask(1,dfn[y],dfn[x],1,n);
		change(1,dfn[y],dfn[x],1,n,z);
		cnt[++t]=ans;
		print(ans);
	}
	for(re i=1;i<=t;i++)  swap(cnt[i].sum[0],cnt[i].sum[1]);
	while(top1>0)  cnt[++t]=instack[top1--];
	tree fin;
	fin.add=fin.ma=fin.sum[0]=fin.sum[1]=0;
	fin.mi=1e18;
	for(re i=1;i<=t;i++)  fin=merge(fin,cnt[i]);
	print(fin);
	return fin.sum[0];
}
void solve()
{
	cin>>n;
	init();
	for(re i=1;i<=n;i++)  scanf("%lld",&a[i]);
	for(re i=1;i<n;i++)
	{
		int x,y;
		scanf("%lld%lld",&x,&y);
		addedge(x,y);
	}
	dfs1(1,1);dfs2(1,1);bulid(1,1,n);
//	for(re i=1;i<=n;i++)  printf("%lld ",dfn[i]);
	cin>>q;
	while(q--)
	{
		int x,y,z;
		scanf("%lld%lld%lld",&x,&y,&z);	
		printf("%lld\n",qchain(x,y,z));
	}
}
signed main()
{
    int T=1;
    cin>>T;
    for(int index=1;index<=T;index++)
    {
//        printf("Case #%lld:\n",index);
        solve();
//        puts("");
    }
    return 0;
}
/*


2
5
1
2
3
4
5
1 2
2 3
3 4
4 5
1
1 5 1

5
1
2
3
4
5
1 2
1 3
2 4
2 5
2
4 5 2
3 4 1

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值