列表

详情


NC20449. [TJOI2015]旅游

描述

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

输入描述

第一行输入一个正整数N,表示城市个数。
接下来一行输入N个正整数表示每座城市宝石的最初价格p,每个宝石的初始价格不超过100。
第三行开始连续输入N-1行,每行有两个数字x和y。表示x城市和y城市有一条路径。城市编号从1开始。
下一行输入一个整数Q,表示询问次数。
接下来Q行,每行输入三个正整数a,b,v,表示ZJY从a旅游到b,城市宝石上涨v。
1 ≤ N ≤ 50000, 1 ≤ Q ≤ 50000

输出描述

对于每次询问,输出ZJY可能获得的最大利润,如果亏本则输出0。

示例1

输入:

3
1 2 3
1 2
2 3
2
1 2 100
1 3 100

输出:

1
1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(clang++11) 解法, 执行用时: 165ms, 内存消耗: 12176K, 提交时间: 2021-04-24 17:51:44

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e4+5;
int p[N];
vector<int>G[N];
int sz[N],dep[N],son[N],f[N];
void dfs(int u,int fa)
{
	sz[u]=1;dep[u]=dep[fa]+1;f[u]=fa;
	for(int v:G[u])
	{
		if(v==fa)	continue;
		dfs(v,u);
		sz[u]+=sz[v];
		if(sz[son[u]]<sz[v])	son[u]=v;
	}
}

int top[N],idx[N],id,val[N];
void DFS(int u,int tp)
{
	idx[u]=++id;
	top[u]=tp;
	val[id]=p[u];
	if(!son[u])	return;
	DFS(son[u],tp);
	for(int v:G[u])
	{
		if(!idx[v])
		{
			DFS(v,v);
		}
	}
}

struct SegTree{
	int l,r,mi,mx,lmx,rmx,lz;
	SegTree	()	{l=r=mx=mi=lz=0;lmx=rmx=0;}
}Tr[N<<2];

void pushup(int u)
{
	Tr[u].mx=max(Tr[u<<1].mx,Tr[u<<1|1].mx);
	Tr[u].mi=min(Tr[u<<1].mi,Tr[u<<1|1].mi);
	Tr[u].lmx=max(Tr[u<<1].mx-Tr[u<<1|1].mi,max(Tr[u<<1].lmx,Tr[u<<1|1].lmx));
	Tr[u].rmx=max(Tr[u<<1|1].mx-Tr[u<<1].mi,max(Tr[u<<1].rmx,Tr[u<<1|1].rmx));
}

void pushdown(int u)
{
	if(Tr[u].lz)
	{
		Tr[u<<1].mx+=Tr[u].lz;
		Tr[u<<1|1].mx+=Tr[u].lz;
		Tr[u<<1].mi+=Tr[u].lz;
		Tr[u<<1|1].mi+=Tr[u].lz;
		Tr[u<<1].lz+=Tr[u].lz;
		Tr[u<<1|1].lz+=Tr[u].lz;
		Tr[u].lz=0;
	}
}

void build(int u,int l,int r)
{
	Tr[u].l=l,Tr[u].r=r;
	if(l==r)
	{
		Tr[u].mx=Tr[u].mi=val[l	];
		return;
	}
	int mid=(l+r)>>1;
	build(u<<1,l,mid);
	build(u<<1|1,mid+1,r);
	pushup(u);
}

void update(int u,int L,int R,int k)
{
	if(L>Tr[u].r||R<Tr[u].l)	return;
	if(L<=Tr[u].l&&R>=Tr[u].r)
	{
		Tr[u].mx+=k;
		Tr[u].mi+=k;
		Tr[u].lz+=k;
		return;
	}
	pushdown(u);
	update(u<<1,L,R,k);
	update(u<<1|1,L,R,k);
	pushup(u);
}

SegTree merge(SegTree l,SegTree r)
{
	SegTree res;
	res.mx=max(l.mx,r.mx);
	res.mi=min(l.mi,r.mi);
	res.lmx=max(l.mx-r.mi,max(l.lmx,r.lmx));
	res.rmx=max(r.mx-l.mi,max(l.rmx,r.rmx));
	return res;
}

SegTree query(int u,int L,int R)
{
	if(L<=Tr[u].l&&Tr[u].r<=R)	return Tr[u];
	pushdown(u);
	int mid=(Tr[u].r+Tr[u].l)>>1;
	if(R<=mid)	return query(u<<1,L,R);
	if(L>mid)	return query(u<<1|1,L,R);
	return merge(query(u<<1,L,R),query(u<<1|1,L,R));
}

void Treeupdate(int u,int v,int k)
{
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])	swap(u,v);
		update(1,idx[top[u]],idx[u],k);
		u=f[top[u]];
	}
	if(dep[u]<dep[v])	swap(u,v);
	update(1,idx[v],idx[u],k);
}

int Treequery(int u,int v)
{
	SegTree x,y;//x维护左 y维护右
	x.mi=y.mi=2e9;
	while(top[u]!=top[v])
	{
		if(dep[top[u]]<dep[top[v]])
		{
			x=merge(query(1,idx[top[v]],idx[v]),x);
			v=f[top[v]];
		}
		else
		{
			y=merge(query(1,idx[top[u]],idx[u]),y); 
			u=f[top[u]];
		}
	}
	if(dep[u]<dep[v])	x=merge(query(1,idx[u],idx[v]),x);
	else				y=merge(query(1,idx[v],idx[u]),y);
	swap(y.rmx,y.lmx);
	return merge(y,x).rmx;
}

int main()
{
  	int n;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d",&p[i]);
	for(int i=1;i<n;i++)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		G[u].push_back(v);
		G[v].push_back(u);
	}
	dfs(1,1);
	DFS(1,1);
	build(1,1,n);
	int Q;
	scanf("%d",&Q);
	while(Q--)
	{
		int a,b,v;
		scanf("%d%d%d",&a,&b,&v);
		printf("%d\n",Treequery(a,b));
		Treeupdate(a,b,v);
	}
	return 0;
}
/*
3
1 2 3
1 3
2 3
2
1 2 100
1 3 100
*/

上一题