hdu 5052(Yaoge’s maximum profit) 树链剖分(方向)

思路: 在线段树节点中维护四个值,1.maxx , 2. minn, 3 .best0 4 best1  分别表示当前区间的最大值 ,最小值,从线段树左子树向右子树走的最大盈利和右子树向左子树走的最大盈利,然后就是在x向y走的时候根据当前是x跳到父节点还是y调到父节点来改变方向,在跳的过程中维护4个变量,maxu ,minu ,maxv , minv 和 两个临时变量, 分别表示 x已经走过的最大值和最小值, y已经走过的最大值和最小值,和当前(刚刚) x(或者y ) 跳过的最大最小值。 答案就很明显了。 1 跳过的一段的best 2,2.best=max(best,tmpmx-minu);  3.  best=max(best,maxv-tmpmn);   4. best=max(best,tmpmx-minu); 5.best=max(best,maxv-tmpmn); 

代码: 

#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)

using namespace std;
typedef long long ll;
const ll inf=1e18+5;
const int N =5e4+5;

struct eee
{
    int v;
    int next;
}edge[N*2];
int tot,head[N];

struct node
{
    int l,r;
    ll mx,mn;
    ll best0,best1;
    ll lz;
}tr[N<<2];

int fat[N];
int dep[N];
int siz[N];
int son[N];
int rak[N];
int top[N];
int idd[N];
int cnt;

int n,m,r;
ll a[N];

void init()
{
    tot=0;
    cnt=0;
    for(int i=0;i<=n;i++){
        head[i]=-1;
        son[i]=0;
        siz[i]=0;
    }
}

void add(int u,int v)
{
    edge[++tot].v=v; edge[tot].next=head[u]; head[u]=tot;
}

void dfs1(int u,int fa,int deep)
{
    fat[u]=fa;
    dep[u]=deep;
    siz[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==fa) continue;
        dfs1(v,u,deep+1);
        siz[u]+=siz[v];
        if(son[u]==0||siz[v]>siz[son[u]]){
            son[u]=v;
        }
    }
}

void dfs2(int u,int t)
{
    top[u]=t;
    idd[u]=++cnt;
    rak[cnt]=u;
    if(!son[u]) return ;
    dfs2(son[u],t);

    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v!=son[u]&&v!=fat[u]){
            dfs2(v,v);
        }
    }
}

void push_up(int i)
{
    tr[i].mn=min(tr[lson].mn,tr[rson].mn);
    tr[i].mx=max(tr[lson].mx,tr[rson].mx);
    tr[i].best0=max(tr[lson].best0,tr[rson].best0);
    tr[i].best1=max(tr[lson].best1,tr[rson].best1);
    tr[i].best0=max(tr[i].best0,tr[rson].mx-tr[lson].mn);
    tr[i].best1=max(tr[i].best1,tr[lson].mx-tr[rson].mn);
}

void push_down(int i)
{
    ll &lz=tr[i].lz;
    if(lz)
    {
        tr[lson].mx+=lz; tr[lson].mn+=lz; tr[lson].lz+=lz;
        tr[rson].mx+=lz; tr[rson].mn+=lz; tr[rson].lz+=lz;
        lz=0;
    }
}

void build(int i,int l,int r)
{
    tr[i].l=l; tr[i].r=r; tr[i].best0=tr[i].best1=0;
    tr[i].mx=0; tr[i].mn=inf; tr[i].lz=0;
    if(l==r){
        tr[i].mn=tr[i].mx=a[rak[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid);
    build(rson,mid+1,r);
    push_up(i);
}

void update(int i,int l,int r,ll val)
{
    if(tr[i].l==l&&tr[i].r==r){
        tr[i].lz+=val;
        tr[i].mx+=val;
        tr[i].mn+=val;
        return ;
    }
    push_down(i);
    int mid=(tr[i].l+tr[i].r)>>1;
    if(r<=mid) update(lson,l,r,val);
    else if(l>mid) update(rson,l,r,val);
    else{
        update(lson,l,mid,val);
        update(rson,mid+1,r,val);
    }
    push_up(i);
}

ll query(int i,int l,int r,int dir,ll &mx,ll &mn)
{
    if(tr[i].l==l&&tr[i].r==r){
        mx=max(tr[i].mx,mx);
        mn=min(tr[i].mn,mn);
        if(dir==0) return tr[i].best0;
        else return tr[i].best1;
    }
    push_down(i);
    int mid=(tr[i].l+tr[i].r)>>1;
    if(r<=mid) return query(lson,l,r,dir,mx,mn);
    else if(l>mid) return query(rson,l,r,dir,mx,mn);
    else{
        ll mx1,mx2,mn1,mn2,best;
        mx1=mx2=best=0; mn1=mn2=inf;
        ll tmpl=query(lson,l,mid,dir,mx1,mn1);
        ll tmpr=query(rson,mid+1,r,dir,mx2,mn2);
        mx=max(mx1,mx2); mn=min(mn1,mn2);
        best=max(tmpl,tmpr);
        if(dir==0) best=max(best,mx2-mn1);
        else best=max(best,mx1-mn2);
        return best;
    }
}

ll querys(int x,int y,ll val)
{
    ll best=0;
    int fx=top[x]; int fy=top[y];
    ll maxu,minu,maxv,minv;
    maxu=maxv=0;
    minu=minv=inf;
    ll tmpmx,tmpmn;
    while(fx!=fy)
    {
        if(dep[fx]>=dep[fy]){
            tmpmx=0; tmpmn=inf;
            best=max(best,query(1,idd[fx],idd[x],1,tmpmx,tmpmn));
            best=max(best,tmpmx-minu);
            best=max(best,maxv-tmpmn);
            //cout<<"** tmpmx "<<tmpmx<<" tmpmn "<<tmpmn<<endl;
            maxu=max(maxu,tmpmx);
            minu=min(minu,tmpmn);
            update(1,idd[fx],idd[x],val);
            x=fat[fx]; fx=top[x];
        }
        else{
            tmpmx=0; tmpmn=inf;
            best=max(best,query(1,idd[fy],idd[y],0,tmpmx,tmpmn));
            best=max(best,tmpmx-minu);
            best=max(best,maxv-tmpmn);
            //cout<<"tmpmx "<<tmpmx<<" tmpmn "<<tmpmn<<endl;
            maxv=max(maxv,tmpmx);
            minv=min(minv,tmpmn);
            //cout<<"yyyy"<<endl;
            update(1,idd[fy],idd[y],val);
            //cout<<"lalal"<<endl;
            y=fat[fy]; fy=top[y];
        }
    }

    if(idd[x]<=idd[y]){
        tmpmx=0; tmpmn=inf;
        best=max(best,query(1,idd[x],idd[y],0,tmpmx,tmpmn));
        best=max(best,tmpmx-minu);
        best=max(best,maxv-tmpmn);
        update(1,idd[x],idd[y],val);
        //cout<<"lalal"<<endl;
    }
    else{
        tmpmx=0; tmpmn=inf;
        best=max(best,query(1,idd[y],idd[x],1,tmpmx,tmpmn));
        best=max(best,tmpmx-minu);
        best=max(best,maxv-tmpmn);
        //cout<<"tmpmx "<<tmpmx<<" tmpmn "<<tmpmn<<endl;
        update(1,idd[y],idd[x],val);
    }
    return best;
}


int main()
{
    int T,q;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        int u,v;
        for(int i=1;i<n;i++){
            scanf("%d %d",&u,&v);
            add(u,v);
            add(v,u);
        }
        dfs1(1,1,0);
        dfs2(1,1);
        build(1,1,n);
        /*
        for(int i=1;i<=n;i++){
            cout<<"*** fat "<<fat[i]<<" dep "<<dep[i]<<" siz "<<siz[i]<<" son "<<son[i]<<" rak "<<rak[i]<<" top "<<top[i]<<" idd "<<idd[i]<<endl;
        }
        */

        scanf("%d",&q);
        ll val;
        while(q--)
        {
            scanf("%d %d %lld",&u,&v,&val);
            ll ans=querys(u,v,val);
            printf("%lld\n",ans);
        }

    }
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值