zoukankan      html  css  js  c++  java
  • Hdu 5052 Yaoge’s maximum profit(树链剖分)

    题目大意:

    给出一棵树。每一个点有商店。每一个商店都有一个价格,Yaoge每次从x走到y都能够在一个倒卖商品,从中得取利益。当然,买一顶要在卖之前。可是没次走过一条路,这条路上的全部商品都会添加一个v。

    输出每次的最大利益。


    思路分析:

    非常easy想到树链剖分,但是关键在于怎样维护这样一个变量。使得每次都要让买的再卖的前面。

    维护变量 ltr 和 rtl 。表示从左去右和从右去左。

    剖分熟练的时候。推断x 和 y的深度,一步一步往上爬。

    然后维护区间最大值和最小值。爬的时候更新答案。



    。。。4921ms...小孩子不要看。。。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #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[root[y]])
            {
                tr=query(1,1,n,w[root[y]],w[y],1,tmax,tmin);
                ry=max(ry,tr);
                ry=max(ry,maxy-tmin);
                maxy=max(maxy,tmax);
                miny=min(miny,tmin);
                ans=max(ans,ry);
                y=pre[root[y]];
            }
            else
            {
                tr=query(1,1,n,w[root[x]],w[x],0,tmax,tmin);
                rx=max(rx,tr);
                rx=max(rx,tmax-minx);
                maxx=max(tmax,maxx);
                minx=min(tmin,minx);
                ans=max(ans,rx);
                x=pre[root[x]];
            }
        }
        if(dep[x]<dep[y])
        {
            tr=query(1,1,n,w[x],w[y],1,tmax,tmin);
            ans=max(ans,tr);
            ans=max(ans,maxy-tmin);
            maxy=max(tmax,maxy);
            miny=min(tmin,miny);
            ans=max(ans,maxy-minx);
        }
        else
        {
            tr=query(1,1,n,w[y],w[x],0,tmax,tmin);
            ans=max(ans,tr);
            ans=max(ans,tmax-minx);
            maxx=max(tmax,maxx);
            minx=min(tmin,minx);
            ans=max(ans,maxy-minx);
        }
        return ans;
    }
    void work(int x,int y,int val)
    {
        while(root[x]!=root[y])
        {
            if(dep[root[x]]<dep[root[y]])swap(x,y);
            update(1,1,n,w[root[x]],w[x],val);
            x=pre[root[x]];
        }
        if(dep[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;
    }
    


  • 相关阅读:
    Visual Studio Code 配置C/C++环境
    二叉链的基本操作
    回文自动机
    吊打线段树的超级树状数组
    Treap平衡树
    uni-app nvue页面动态修改导航栏按钮
    uni-app map组件关于marker标记点动态设置的问题
    uni-app 提示 v-for 暂不支持循环数据
    uni-app APP端隐藏导航栏自定义按钮
    uni-app路径规划(打开第三方地图实现)
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5354943.html
Copyright © 2011-2022 走看看