[TJOI2015]旅游

Posted by Dispwnl on December 4, 2018

题目

题目描述

为了提高智商,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,表示ZY从a旅游到b,城市宝石上涨v。

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

1
1

说明

数据范围

对于30%的数据,有0 < N ≤ 100, 0 < Q ≤ 10000。

对于100%的数据,有0 < N ≤ 50000, 0 < Q ≤ 50000。

题解

出题人这个语文表达能力真的……

题目大意:

给定一棵树,每次询问从$a$走到$b$,选择两个城市$c,d(dis_{a,c}<dis_{a,d})$,使得$w_d-w_c$的值最大,求这个最大值,并且要求维护链上修改

如果是一个序列,显然用线段树就可以简单维护,这是放到树上的,所以用树链剖分维护了

考虑树链剖分处理询问的过程,两点深度大的往上沿着重链跳,直到跳到$LCA$

这样有两个问题:

  • 一条链上不一定是一个编号连续的区间
  • 左边链是由大的编号(线段树编号)跳到小的编号

所以要分左右链讨论,对于第一个问题,在跳链的时候维护一个最大(右边链)最小(左边链)值即可;对于第二个问题,在线段树上同时维护从左到右和从右到左的最大差值即可

对树链剖分跳链分情况讨论好像还挺常见的qwq

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<algorithm>
# define tl (k<<1)
# define tr (k<<1|1)
# define mid (l+r>>1)
using namespace std;
const int MAX=5e4+5;
struct p{
    int minn,maxn,d,_d,tag;
    p(){d=_d=-2e9;}
}s[MAX<<2];
struct q{
    int x,y;
}c[MAX<<1];
int n,m,num,cnt;
int h[MAX],d[MAX],f[MAX],siz[MAX],son[MAX],w[MAX],re[MAX],top[MAX],id[MAX];
int read()
{
    int x=0,fl=1;
    char ch=getchar();
    for(;!isdigit(ch);fl=(ch=='-')?-1:1,ch=getchar());
    for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
    return x*fl;
}
void add()
{
    int x=read(),y=read();
    c[++num]=(q){h[x],y},h[x]=num;
    c[++num]=(q){h[y],x},h[y]=num;
}
void dfs(int x=1,int fa=0)
{
    f[x]=fa,d[x]=d[fa]+(siz[x]=1);
    for(int i=h[x];i;i=c[i].x)
      if(c[i].y^fa)
      {
      	dfs(c[i].y,x),siz[x]+=siz[c[i].y];
      	if(siz[son[x]]<siz[c[i].y]) son[x]=c[i].y;
      }
}
void dfs1(int x=1,int tp=1)
{
    top[x]=tp,id[x]=++cnt,re[cnt]=x;
    if(!son[x]) return;
    dfs1(son[x],tp);
    for(int i=h[x];i;i=c[i].x)
      if((c[i].y^f[x])&&(c[i].y^son[x])) dfs1(c[i].y,c[i].y);
}
p pus(p b,p c,int Tag=0)
{
    p a;
    a.minn=min(b.minn,c.minn);
    a.maxn=max(b.maxn,c.maxn);
    a.d=max(c.maxn-b.minn,max(b.d,c.d));
    a._d=max(b.maxn-c.minn,max(b._d,c._d));
    return a.tag=Tag,a;
}
void build(int l=1,int r=n,int k=1)
{
    if(l==r) return void(s[k].minn=s[k].maxn=w[re[l]]);
    build(l,mid,tl),build(mid+1,r,tr),s[k]=pus(s[tl],s[tr]);
}
void down(int k)
{
    if(!s[k].tag) return;
    int f=s[k].tag;
    s[k].tag=0,s[tl].tag+=f,s[tr].tag+=f,s[tl].minn+=f,s[tl].maxn+=f,s[tr].minn+=f,s[tr].maxn+=f;
}
void change(int l,int r,int k,int L,int R,int dis)
{
    if(l==L&&r==R)
    {
        s[k].minn+=dis,s[k].maxn+=dis;
        return void(s[k].tag+=dis);
    }
    down(k);
    if(R<=mid) change(l,mid,tl,L,R,dis);
    else if(L>mid) change(mid+1,r,tr,L,R,dis);
    else change(l,mid,tl,L,mid,dis),change(mid+1,r,tr,mid+1,R,dis);
    s[k]=pus(s[tl],s[tr],s[k].tag);
}
void CHANGE(int x,int y,int dis)
{
    while(top[x]^top[y])
    {
        if(d[top[x]]<d[top[y]]) swap(x,y);
        change(1,n,1,id[top[x]],id[x],dis),x=f[top[x]];
    }
    if(d[x]>d[y]) swap(x,y);
    change(1,n,1,id[x],id[y],dis);
}
p ask(int l,int r,int k,int L,int R)
{
    if(l==L&&r==R) return s[k];
    down(k);
    if(R<=mid) return ask(l,mid,tl,L,R);
    if(L>mid) return ask(mid+1,r,tr,L,R);
    return pus(ask(l,mid,tl,L,mid),ask(mid+1,r,tr,mid+1,R));
}
int ASK(int x,int y)
{
    int ans=0,maxn_l=-2e9,maxn_r=-2e9,minn_r=2e9,minn_l=2e9;
    p tt;
    while(top[x]^top[y])
    {
        if(d[top[x]]<d[top[y]])
        {
            tt=ask(1,n,1,id[top[y]],id[y]),y=f[top[y]];
            ans=max(ans,max(tt.d,maxn_r-tt.minn)),maxn_r=max(maxn_r,tt.maxn),minn_r=min(minn_r,tt.minn);
        }
        else
        {
            tt=ask(1,n,1,id[top[x]],id[x]),x=f[top[x]];
            ans=max(ans,max(tt._d,tt.maxn-minn_l)),maxn_l=max(maxn_l,tt.maxn),minn_l=min(minn_l,tt.minn);
        }
    }
    if(d[x]>d[y])
    {
        tt=ask(1,n,1,id[y],id[x]);
        ans=max(ans,max(tt._d,tt.maxn-minn_l)),minn_l=min(minn_l,tt.minn);
    }
    else
    {
        tt=ask(1,n,1,id[x],id[y]);
        ans=max(ans,max(tt.d,maxn_r-tt.minn)),maxn_r=max(maxn_r,tt.maxn);
    }
    return max(ans,maxn_r-minn_l);
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i)
      w[i]=read();
    for(int i=1;i<n;++i,add());
    dfs(),dfs1(),build(),m=read();
    for(int i=1,a,b,c;i<=m;++i)
      a=read(),b=read(),c=read(),printf("%d\n",ASK(a,b)),CHANGE(a,b,c);
    return 0;
}