P3976 [TJOI2015]旅游

P3976 [TJOI2015]旅游

分析

这题和染色,是非常类似的题型。我们从头来看。

本题要求我们动态维护一条链上,从起点到终点中,挑选一个点为买,再挑选一个点为卖,能得到的最大利润(若利润为负则为0,即可以理解为不买不卖)

需要注意的是,因为买的点编号一定要比卖的点靠前(最多刚买的就卖,但这跟不买是一样的),因此我们无法简单的维护一个最大最小值就结束了。

那我们维护什么呢?从最大子段和中得到的提醒,我们维护以下几个值

  • mx,mi,即一段的最大最小值
  • lmx,表示为从左向右,能得到的利润最大值。(线段树中的从左到右,即为编号从小到大)
  • rmx,表示为从右向左,能得到的利润最大值。(线段树中的从右向左,记为编号从大到小)
  • tag,很常规的区间加懒标记,不多解释了。

其中,关于lmxrmx的维护,我们来看一下

但请一定记住这点:注意!注意!注意!,是有顺序问题的,因为我们是从起点到终点,是有方向的

  • lmx的维护,我们分为两部分:
    • 不跨左右区间,则取左右区间lmx即可,即为max(left.lmx,right.lmx)
    • 跨左右区间,则为从左区间到右区间,则取右区间的最大值-左区间的最小值即可,即为right.mx - left.mi
  • rmx的维护,也分为两部分
    • 不跨左右区间,则取左右区间rmx即可,即为max(left.rmx,right.rmx)
    • 跨左右区间,则为从右区间到左区间,则取左区间的最大值-右区间的最小值即可,即为left.mx-right.mi

我们需要维护从起点翻上来的所有链的信息,我们记为L,还需维护从终点翻上来的所有链的信息,我们记为R

我们首先完成一下初始化

L.lmx = L.rmx = 0;
L.mx = -INF,L.mi = INF;
R = L;

接下来,就要说卡了我超久的一点了。记得我们之前提到的方向问题了嘛?

当我们在更新L,R时,我们需要注意两点:

  1. 一定要分清楚,更新的是从起点上来的L,还是从终点上来的R
  2. 同时在更新L或R时,因为此时用来更新的L或R的链肯定比原来的L,R的编号小,因此都是在L,R左边,要按新区间为左区间,L,R为右区间去更新。

在完成这些之后,最后的答案由两类决定,取其中最大值:

  1. 不跨区间,则去L的rmx与R的lmx的最大值,即max(L.rmx,R.lmx)
  2. 跨区间,则取R的最大值-L的最小值,即R.mx - L.mi

这题,很重要的一点就是,有方向问题,方向问题在树链剖分中也比较常见,需要注意此时操作的是起点的链还是终点的链了

另外在查询的时候,我们需要注意,只有在查询区间横跨左右区间时,我们才进行合并操作,否则直接返回左区间,右区间或整个区间即可

我们来看看代码

Ac_code

#include<bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10,M = N*2,INF = 0x3f3f3f3f;
struct Node
{
    int l,r,mx,mi,lmx,rmx,tag;
}tr[N<<2];
int h[N],e[M],ne[M],w[N],idx;
int sz[N],dep[N],fa[N],son[N];
int top[N],id[N],nw[N],ts;
int n,m;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}

void dfs1(int u,int pa,int depth)
{
    sz[u] = 1,fa[u] = pa,dep[u] = depth;
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==pa) continue;
        dfs1(j,u,depth+1);
        if(sz[j]>sz[son[u]]) son[u] = j;
        sz[u] += sz[j];
    }
}

void dfs2(int u,int tp)
{
    top[u] = tp,id[u] = ++ts,nw[ts] = w[u];
    if(!son[u]) return ;
    dfs2(son[u],tp);
    for(int i=h[u];~i;i=ne[i])
    {
        int j = e[i];
        if(j==fa[u]||j==son[u]) continue;
        dfs2(j,j);
    }
}

void push(Node &u,Node l,Node r)
{
    u.lmx = max(max(l.lmx,r.lmx),r.mx - l.mi);
    u.rmx = max(max(l.rmx,r.rmx),l.mx - r.mi);
    u.mx = max(l.mx,r.mx);
    u.mi = min(l.mi,r.mi);
}

void pushup(int u)
{
    push(tr[u],tr[u<<1],tr[u<<1|1]);
}

void change(Node &u,int k)
{
    u.tag += k;
    u.mx += k;
    u.mi += k;
} 

void pushdown(int u)
{
    auto &root = tr[u],&left = tr[u<<1],&right = tr[u<<1|1];
    if(root.tag)
    {
        change(left,root.tag);
        change(right,root.tag);
        root.tag = 0;
    }
}

void build(int u,int l,int r)
{
    if(l==r)
    {
        tr[u] = {l,r,nw[l],nw[l]};
        return ;
    }
    tr[u] = {l,r};
    int mid = l + r >> 1;
    build(u<<1,l,mid),build(u<<1|1,mid+1,r);
    pushup(u);
}

void modify(int u,int l,int r,int k)
{
    if(l<=tr[u].l&&tr[u].r<=r)
    {
        change(tr[u],k);
        return ;
    }
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    if(l<=mid) modify(u<<1,l,r,k);
    if(r>mid) modify(u<<1|1,l,r,k);
    pushup(u);
}

Node 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].l + tr[u].r >> 1;
    if(l>mid) return query(u<<1|1,l,r);
    else if(r<=mid) return query(u<<1,l,r);
    else{ 
        Node res;
        push(res,query(u<<1,l,r),query(u<<1|1,l,r));
        return res;
    }
}

int main()
{
    scanf("%d",&n);
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++) scanf("%d",w+i);
    for(int i=0;i<n-1;i++) 
    {
        int a,b;
        scanf("%d%d",&a,&b);
        add(a,b),add(b,a);
    }
    dfs1(1,-1,1);
    dfs2(1,1);
    build(1,1,n);
    Node L,R;
    scanf("%d",&m);
    while(m--)
    {
        L.lmx = L.rmx = 0;
        L.mx = -INF,L.mi = INF;
        R = L;
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        while(top[a]!=top[b])
        {
            if(dep[top[a]]<dep[top[b]]) 
            {
                push(R,query(1,id[top[b]],id[b]),R);
                modify(1,id[top[b]],id[b],c);
                b = fa[top[b]];
            }
            else
            {
                push(L,query(1,id[top[a]],id[a]),L);
                modify(1,id[top[a]],id[a],c);
                a = fa[top[a]];
            }
        }
        if(dep[a]<dep[b]) 
        {
            push(R,query(1,id[a],id[b]),R);
            modify(1,id[a],id[b],c);
        }
        else
        {
            push(L,query(1,id[b],id[a]),L);
            modify(1,id[b],id[a],c);
        }
        printf("%d\n",max(max(L.rmx,R.lmx),R.mx - L.mi));
    }
    return 0;
}
posted @ 2022-04-08 18:11  艾特玖  阅读(107)  评论(0)    收藏  举报