zoukankan      html  css  js  c++  java
  • HDU 5692

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5692

    Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

    Problem Description
    百度科技园内有n个零食机,零食机之间通过n−1条路相互连通。每个零食机都有一个值v,表示为小度熊提供零食的价值。

    由于零食被频繁的消耗和补充,零食机的价值v会时常发生变化。小度熊只能从编号为0的零食机出发,并且每个零食机至多经过一次。另外,小度熊会对某个零食机的零食有所偏爱,要求路线上必须有那个零食机。

    为小度熊规划一个路线,使得路线上的价值总和最大。

    Input
    输入数据第一行是一个整数T(T≤10),表示有T组测试数据。
    对于每组数据,包含两个整数n,m(1≤n,m≤100000),表示有n个零食机,m次操作。
    接下来n−1行,每行两个整数x和y(0≤x,y<n),表示编号为x的零食机与编号为y的零食机相连。
    接下来一行由n个数组成,表示从编号为0到编号为n−1的零食机的初始价值v(|v|<100000)。
    接下来m行,有两种操作:0 x y,表示编号为x的零食机的价值变为y;1 x,表示询问从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。
    本题可能栈溢出,辛苦同学们提交语言选择c++,并在代码的第一行加上:
    `#pragma comment(linker, "/STACK:1024000000,1024000000") `

    Output
    对于每组数据,首先输出一行”Case #?:”,在问号处应填入当前数据的组数,组数从1开始计算。
    对于每次询问,输出从编号为0的零食机出发,必须经过编号为x零食机的路线中,价值总和的最大值。

    Sample Input
    1
    6 5
    0 1
    1 2
    0 3
    3 4
    5 3
    7 -5 100 20 -5 -7
    1 1
    1 3
    0 2 -1
    1 1
    1 5

    Sample Output
    Case #1:
    102
    27
    2
    20

     

    题解:

    题目给出n个点和n-1条边,并且是连通图,那么显然是一棵树;

    一棵无向树,我们可以任意取一个节点作为树根,根据题意取编号为0的节点为树根;

    那么,对于其他的1~n-1号节点,从树根(0号节点)到它们只有唯一一条路径,

    假设sum[i]代表从0号节点到i号节点这条路径上所有的点(包括节点0和i)的value值之和;

    (换句话说,假设从root=0,到i节点的唯一一条简单路径为0-1-3-5-i,那么 sum[i] = value[0] + value[1] + value[3] + value[5] + value[i];)

    then,对于题目中描述的两种操作:

    ①修改节点i的value[i]值:

      一旦修改value[i],会影响到以i为树根的子树内的所有节点的sum[],

      假设value[i]+=k,那么其正科统领的一整棵子树上的节点上的sum[]都要加上k;

    ②查询:从0号节点出发,经过节点x,走一条简单路径,所经过的所有节点的value值之和的最大值:

      显然,这就是枚举节点x统领的子树上所有的节点的sum[]值,找到其中最大的就行;

    (注:在上面,节点x统领的子树内所有的点,包含节点x自己)

    那么,如果我们使用DFS序把整棵树“拍平”,把他们排列到一串序列中……

    这个序列中,节点x的in[x]和out[x]代表:[ in[x] , out[x] ]区间内的点正好是节点x统领的子树内的所有节点;

    那么对于上面两种操作,我们从可以从“树上修改,树上查询”变成“区间修改,区间查询”……

    即:

      ①x节点统领的子树内,所有节点的sum[]+=k → [ in[x] , out[x] ]区间内所有节点的sum[]+=k;

      ②x节点统领的子树内,查询所有节点中sum[]的最大值 → 查询[ in[x] , out[x] ]区间内所有节点的sum[]最大值;

    显然,如果使用线段树进行维护,两种操作就都从O(n)时间复杂度变成了O(lgn)的时间复杂度;

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    const int maxn=100000+5;
    const LL INF=1e18;
    
    int n,m;
    LL val[maxn],sum[maxn];
    
    //邻接表-st
    struct Edge{
        int u,v;
        Edge(int u,int v){this->u=u,this->v=v;}
    };
    vector<Edge> E;
    vector<int> G[maxn];
    void Adjacency_List_Init(int l,int r)
    {
        E.clear();
        for(int i=l;i<=r;i++) G[i].clear();
    }
    void addedge(int u,int v)
    {
        E.push_back(Edge(u,v));
        E.push_back(Edge(v,u));
        int _size=E.size();
        G[u].push_back(_size-2);
        G[v].push_back(_size-1);
    }
    //邻接表-ed
    
    //dfs序-st
    int dfs_clock;
    bool vis[maxn];
    int in[maxn],out[maxn];
    int peg[maxn];
    inline void DFS_Init()
    {
        dfs_clock=0;
        memset(vis,0,sizeof(vis));
    }
    void dfs(int now)
    {
        in[now]=++dfs_clock;
        peg[in[now]]=now;
    
        vis[now]=1;
        for(int i=0,_size=G[now].size();i<_size;i++)
        {
            int nxt=E[G[now][i]].v;
            if(!vis[nxt])
            {
                sum[nxt]=sum[now]+val[nxt];
                dfs(nxt);
            }
        }
    
        out[now]=dfs_clock;
    }
    //dfs序-ed
    
    //线段树-st
    struct Node{
        int l,r;
        LL val,lazy;
        void update(LL x)
        {
            val+=x;
            lazy+=x;
        }
    }node[4*maxn];
    void pushdown(int root)
    {
        if(node[root].lazy)
        {
            node[root*2].update(node[root].lazy);
            node[root*2+1].update(node[root].lazy);
            node[root].lazy=0;
        }
    }
    void pushup(int root)
    {
        node[root].val=max(node[root*2].val,node[root*2+1].val);
    }
    void build(int root,int l,int r)
    {
        node[root].l=l; node[root].r=r;
        node[root].val=0; node[root].lazy=0;
        if(l==r) node[root].val=sum[peg[l]];
        else
        {
            int mid=l+(r-l)/2;
            build(root*2,l,mid);
            build(root*2+1,mid+1,r);
            pushup(root);
        }
    }
    void update(int root,int st,int ed,int val)
    {
        if(st>node[root].r || ed<node[root].l) return;
        if(st<=node[root].l && node[root].r<=ed) node[root].update(val);
        else
        {
            pushdown(root);
            update(root*2,st,ed,val);
            update(root*2+1,st,ed,val);
            pushup(root);
        }
    }
    LL query(int root,int st,int ed)
    {
        if(ed<node[root].l || node[root].r<st) return -INF;
        if(st<=node[root].l && node[root].r<=ed) return node[root].val;
        else
        {
            pushdown(root);
            LL lson=query(root*2,st,ed);
            LL rson=query(root*2+1,st,ed);
            pushup(root);
            return max(lson,rson);
        }
    }
    //线段树-ed
    
    
    int main()
    {
        int t;
        scanf("%d",&t);
        for(int kase=1;kase<=t;kase++)
        {
            scanf("%d%d",&n,&m);
    
            Adjacency_List_Init(0,n-1);
            for(int i=1,u,v;i<=n-1;i++)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
    
            for(int i=0;i<n;i++) scanf("%I64d",&val[i]);
    
            DFS_Init();
            sum[0]=val[0];
            dfs(0);
    
            build(1,1,n);
            printf("Case #%d:
    ",kase);
            for(int i=1,type,x,y;i<=m;i++)
            {
                scanf("%d",&type);
                if(type==0)
                {
                    scanf("%d%d",&x,&y);
                    update(1,in[x],out[x],y-val[x]);
                    val[x]=y;
                }
                if(type==1)
                {
                    scanf("%d",&x);
                    printf("%I64d
    ",query(1,in[x],out[x]));
                }
            }
        }
    }

    注意:这里的线段树,是区间更新(一个区间加上一个值),区间查询(一个区间的val维护:区间内所有节点最大值)。

     
  • 相关阅读:
    11个有用的移动网页开发App和HTML5框架
    移动平台前端开发总结(针对iphone,Android等手机)
    uploadify按钮中文乱码问题
    @page指令 validateRequest的作用
    C#,.net获取字符串中指定字符串的个数、所在位置与替换字符串
    lambda函数
    主函数
    Python函数
    猴子
    旋转
  • 原文地址:https://www.cnblogs.com/dilthey/p/8988368.html
Copyright © 2011-2022 走看看