Hdu 5052 Yaoge’s maximum profit(树链剖分)

题目大意:

给出一棵树,每个点有商店,每个商店都有一个价格,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;
}


你可能感兴趣的:(树链剖分)