题目大意:
给出一棵树,每个点有商店,每个商店都有一个价格,Yaoge每次从x走到y都可以在一个倒卖商品,从中得取利益,当然,买一顶要在卖之前。但是没次走过一条路,这条路上的所有商品都会增加一个v。
输出每次的最大利益。
思路分析:
很容易想到树链剖分,可是关键在于如何维护这样一个变量,使得每次都要让买的再卖的前面。
维护变量 ltr 和 rtl ,表示从左去右和从右去左。
剖分熟练的时候,判断x 和 y的深度,一步一步往上爬。
然后维护区间最大值和最小值,爬的时候更新答案。
。。。4921ms...小孩子不要看。。。
#include
#include
#include
#include
#pragma comment(linker,"/STACk:10240000,10240000")
#define maxn 50005
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define lson num<<1,s,mid
#define rson num<<1|1,mid+1,e
using namespace std;
typedef long long ll;
int next[maxn<<1],to[maxn<<1],head[maxn],tot;//临界表
int pre[maxn],root[maxn],siz[maxn],son[maxn],w[maxn],dep[maxn],id;//原树的父亲 链上的根 siz 有最大siz的子树 重新分配的id 深度 getid中来计数的
ll ltr[maxn<<2],rtl[maxn<<2],mx[maxn<<2],mn[maxn<<2],add[maxn<<2];//线段树变量
int n;
void init()
{
pre[1]=0;
dep[1]=0;
tot=0;id=0;
memset(head,0,sizeof head);
memset(add,0,sizeof add);
memset(mn,0,sizeof mn);
memset(mx,0,sizeof mx);
memset(ltr,0,sizeof ltr);
memset(rtl,0,sizeof rtl);
}
void addedge(int u,int v)
{
tot++;
next[tot]=head[u];
to[tot]=v;
head[u]=tot;
}
void dfs(int now)//to get size,son,dep,pre...
{
son[now]=0;
siz[now]=1;
for(int p =head[now]; p ; p=next[p])
{
int t=to[p];
if(t!=pre[now])
{
pre[t]=now;
dep[t]=dep[now]+1;
dfs(t);
if(siz[t]>siz[son[now]])son[now]=t;
siz[now]+=siz[t];
}
}
}
void getid(int now,int rt)//to get w and root...
{
w[now]=++id;
root[now]=rt;
if(son[now])getid(son[now],rt);
for(int p = head[now] ; p ; p=next[p])
{
int t=to[p];
if(t!=son[now]&&t!=pre[now])
getid(t,t);
}
}
void pushdown(int num,int s,int e)
{
if(add[num])
{
int mid=(s+e)>>1;
mx[num<<1]+=add[num];
mx[num<<1|1]+=add[num];
mn[num<<1]+=add[num];
mn[num<<1|1]+=add[num];
add[num<<1]+=add[num];
add[num<<1|1]+=add[num];
add[num]=0;
}
}
void pushup(int num)
{
mx[num]=max(mx[num<<1],mx[num<<1|1]);
mn[num]=min(mn[num<<1],mn[num<<1|1]);
ltr[num]=max(mx[num<<1|1]-mn[num<<1],max(ltr[num<<1],ltr[num<<1|1]));
rtl[num]=max(mx[num<<1]-mn[num<<1|1],max(rtl[num<<1],rtl[num<<1|1]));
if(ltr[num]<0)ltr[num]=0;
if(rtl[num]<0)rtl[num]=0;
}
void update(int num,int s,int e,int l,int r,int val)
{
if(l<=s && r>=e)
{
add[num]+=val;
mx[num]+=val;
mn[num]+=val;
return;
}
pushdown(num,s,e);
int mid=(s+e)>>1;
if(l<=mid)update(lson,l,r,val);
if(r>mid)update(rson,l,r,val);
pushup(num);
}
ll query(int num,int s,int e,int l,int r,int flg,ll &maxv,ll &minv)
{
if(l<=s && r>=e)
{
maxv=mx[num];
minv=mn[num];
if(flg)return ltr[num];
else return rtl[num];
}
int mid=(s+e)>>1;
pushdown(num,s,e);
if(r<=mid)return query(lson,l,r,flg,maxv,minv);
else if(l>mid)return query(rson,l,r,flg,maxv,minv);
else
{
ll r1,r2,n1,n2,m1,m2,ans;
r1=query(lson,l,mid,flg,m1,n1);
r2=query(rson,mid+1,r,flg,m2,n2);
maxv=max(m1,m2);
minv=min(n1,n2);
if(flg)
{
ans=max(r1,r2);
ans=max(ans,m2-n1);
}
else
{
ans=max(r1,r2);
ans=max(ans,m1-n2);
}
ans=max(0LL,ans);
return ans;
}
}
ll fuck(int x,int y)
{
ll ans=0,maxx,minx,maxy,miny,rx,ry;
ll tmax,tmin,tr;
maxx=maxy=0;
minx=miny=Inf;
rx=ry=0;
while(root[x]!=root[y])
{
if(dep[root[x]]dep[y])swap(x,y);
update(1,1,n,w[x],w[y],val);
}
int save[maxn];
inline void scanf_(int &num){
char in;
bool neg=false;
while(((in=getchar()) > '9' || in<'0') && in!='-') ;
if(in=='-'){
neg=true;
while((in=getchar()) >'9' || in<'0');
}
num=in-'0';
while(in=getchar(),in>='0'&&in<='9')
num*=10,num+=in-'0';
if(neg)
num=0-num;
}
inline void printf_(ll num){
bool flag=false;
if(num<0){
putchar('-');
num=-num;
}
int ans[20],top=0;
while(num!=0){
ans[top++]=num%10;
num/=10;
}
if(top==0)
putchar('0');
for(int i=top-1;i>=0;i--){
char ch=ans[i]+'0';
putchar(ch);
}
puts("");
}
int main()
{
int T;
scanf_(T);
while(T--)
{
init();
scanf_(n);
for(int i=1;i<=n;i++)
scanf_(save[i]);
for(int i=1;i<=n-1;i++)
{
int s,e;
scanf_(s);scanf_(e);
addedge(s,e);
addedge(e,s);
}
dfs(1);
getid(1,1);
for(int i=1;i<=n;i++)
update(1,1,n,w[i],w[i],save[i]);
char str[5];
int Q;
scanf_(Q);
while(Q--)
{
int x,y,v;
scanf_(x);
scanf_(y);
scanf_(v);
printf_(fuck(x,y));
work(x,y,v);
}
}
return 0;
}