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

题目大意:

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

输出每次的最大利益。

思路分析:

很容易想到树链剖分,可是关键在于如何维护这样一个变量,使得每次都要让买的再卖的前面。

维护变量 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;
}
时间: 2024-12-09 11:37:21

Hdu 5052 Yaoge’s maximum profit(树链剖分)的相关文章

HDU 5052 Yaoge’s maximum profit 裸树链剖分 2014 ACM/ICPC Asia Regional Shanghai Online

题意: 给定n个点的带点权树. 下面n行给出每个点点权表示每个点买卖鸡腿的价格 下面n-1行给出树边 下面Q个操作 Q行 u, v, val 从u走到v,过程中可以买一个鸡腿,然后到后面卖掉,输出max(0, 最大的收益) 然后给[u,v]路径上点点权+=val 思路: 树链剖分裸题 屌丝题解:点击打开链接 #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include &

hdu 5052 Yaoge’s maximum profit

Yaoge’s maximum profit Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 442    Accepted Submission(s): 122 Problem Description Yaoge likes to eat chicken chops late at night. Yaoge has eaten too

HDU 3966 Aragorn&#39;s Story(树链剖分 模板题)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of enemies who want to invade his kingdom. As Aragorn knows, th

HDU - 3966 Aragorn&#39;s Story(树链剖分入门+线段树)

HDU - 3966 Aragorn's Story Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of ene

HDU 3966 Aragorn&#39;s Story (树链剖分+线段树)

题意:给你一棵树,然后有三种操作 I L R K: 把L与R的路径上的所有点权值加上K D L R K:把L与R的路径上的所有点权值减去K Q X:查询节点编号为X的权值 思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会) 我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便

hdu 4912 Paths on the tree(树链剖分+贪心)

题目链接:hdu 4912 Paths on the tree 题目大意:给定一棵树,和若干个通道,要求尽量选出多的通道,并且两两通道不想交. 解题思路:用树链剖分求LCA,然后根据通道两端节点的LCA深度排序,从深度最大优先选,判断两个节点均没被标 记即为可选通道.每次选完通道,将该通道LCA以下点全部标记. #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #include

(中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are m chain on the tree, Each chain has a certain weight. Coco would like to pick out some chains any two of which do not share common vertices.Find out the

HDU 2460 Network(双连通+树链剖分+线段树)

HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链剖分+线段树处理 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <vector> using namespace std; #pragma comment(linke

hdu 5293 Tree chain problem(树链剖分+树形dp)

题目链接:hdu 5293 Tree chain problem 维护dp[u], sum[u],dp[u]表示以u为根节点的子树的最优值.sum[u]表示以u节点的所有子节点的dp[v]之和.对于边a,b,w,在LCA(a,b)节点的时候进行考虑.dp[u] = min{dp[u], Sum(a,b) - Dp(a,b) + sum[u] | (ab链上的点,不包括u } #pragma comment(linker, "/STACK:1024000000,1024000000")