zoukankan      html  css  js  c++  java
  • HDU 5029 Relief grain --树链剖分第一题

    题意:给一棵树,每次给两个节点间的所有节点发放第k种东西,问最后每个节点拿到的最多的东西是哪种。

    解法:解决树的路径上的修改查询问题一般用到的是树链剖分+线段树,以前不会写,后来学了一下树链剖分,感觉也不是很难,就是把整个数分成很多链,然后一条重链上的点在线段树中位置是连续的,这样使得更新和查询时更加便利。

    这个题目中线段树应该维护的是种类,每次对u-v发放k时,可以让u处+k,v+1处-k,把这些都离线存起来,然后枚举1~n,分别把自己该做的操作都做了,然后统计的时候tree[1].type就是该点的type。

    这题是借鉴别人的代码写的,总算对树链剖分的题有所了解了。

    还有在HDU交C++会爆栈,要加一个扩栈语句,不想加交G++也可以。

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define N 100007
    
    int siz[N];  //子树大小
    int son[N];  //重儿子
    int dep[N];  //深度
    int pos[N];  //在线段树中的位置
    int apos[N]; //线段树中位置对应的点
    int Top[N];  //所在重链的祖先
    int fa[N];   //父节点
    int ans[N];  //答案
    int head[2*N],tot,POS,n,m;
    struct Edge
    {
        int v,next;
    }G[2*N];
    
    struct Tree
    {
        int num,type;
    }tree[4*N];
    
    struct node
    {
        int u,v,z;
        node(){}
        node(int _u,int _v,int _z):u(_u),v(_v),z(_z){}
    };
    vector<node> com;
    vector<int> Q[N];
    
    void init()
    {
        POS = tot = 0;
        memset(head,-1,sizeof(head));
        memset(son,-1,sizeof(son));
        com.clear();
        for(int i=0;i<=n+1;i++)
            Q[i].clear();
    }
    
    void addedge(int u,int v)
    {
        G[tot].v = v, G[tot].next = head[u], head[u] = tot++;
        G[tot].v = u, G[tot].next = head[v], head[v] = tot++;
    }
    
    void pushup(int rt)
    {
        if(tree[2*rt].num >= tree[2*rt+1].num)
            tree[rt].type = tree[2*rt].type;
        else
            tree[rt].type = tree[2*rt+1].type;
        tree[rt].num = max(tree[2*rt].num,tree[2*rt+1].num);
    }
    
    void build(int l,int r,int rt)
    {
        tree[rt].num = 0;
        if(l == r)
        {
            tree[rt].type = l;
            return;
        }
        int mid = (l+r)/2;
        build(l,mid,2*rt);
        build(mid+1,r,2*rt+1);
        pushup(rt);
    }
    
    void update(int l,int r,int pos,int val,int rt)
    {
        if(l == r)
        {
            tree[rt].num += val;
            return;
        }
        int mid = (l+r)/2;
        if(pos <= mid)
            update(l,mid,pos,val,2*rt);
        else
            update(mid+1,r,pos,val,2*rt+1);
        pushup(rt);
    }
    
    void dfs(int u,int f)
    {
        dep[u] = dep[f]+1;
        siz[u] = 1;
        for(int i=head[u];i!=-1;i=G[i].next)
        {
            int v = G[i].v;
            if(v == f) continue;
            fa[v] = u;
            dfs(v,u);
            if(son[u] == -1 || siz[v] > siz[son[u]]) son[u] = v;
            siz[u] += siz[v];
        }
    }
    
    void dfs2(int u,int father)
    {
        pos[u] = ++POS;
        apos[POS] = u;
        Top[u] = father;
        if(son[u] != -1) dfs2(son[u],father);   //有重儿子优先dfs
        for(int i=head[u];i!=-1;i=G[i].next)
        {
            int v = G[i].v;
            if(v != fa[u] && v != son[u])
                dfs2(v,v);
        }
    }
    
    void getcom(int u,int v,int z)
    {
        int fx = Top[u], fy = Top[v];
        while(fx != fy)
        {
            if(dep[fx] < dep[fy])
            {
                swap(u,v);
                swap(fx,fy);
            }
            com.push_back(node(pos[fx],pos[u],z));
            u = fa[fx];
            fx = Top[u];
        }
        if(dep[u] > dep[v]) swap(u,v);
        com.push_back(node(pos[u],pos[v],z));
    }
    
    int main()
    {
        int i,j,maxi,u,v,z;
        while(scanf("%d%d",&n,&m)!=EOF && n+m)
        {
            init();
            for(i=1;i<n;i++)
            {
                scanf("%d%d",&u,&v);
                addedge(u,v);
            }
            dep[1] = 0;
            dfs(1,1);
            dfs2(1,1);
            maxi = 1;
            while(m--)
            {
                scanf("%d%d%d",&u,&v,&z);
                getcom(u,v,z);
                maxi = max(maxi,z);
            }
            int SIZE = com.size();
            for(i=0;i<SIZE;i++)
            {
                int u = com[i].u, v = com[i].v, z = com[i].z;
                Q[u].push_back(z);
                Q[v+1].push_back(-z);
            }
            build(1,maxi,1);
            for(i=1;i<=n;i++)
            {
                sort(Q[i].begin(),Q[i].end());
                int sz = Q[i].size();
                for( j=0;j<sz;j++)
                {
                    int p = Q[i][j];
                    if(p < 0) update(1,maxi,-p,-1,1);
                    else      update(1,maxi,p,1,1);
                }
                ans[apos[i]] = tree[1].type;
                if(tree[1].num == 0) ans[apos[i]] = 0;
            }
            for(i=1;i<=n;i++)
                printf("%d
    ",ans[i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【学习笔记】【C语言】递归
    【学习笔记】【C语言】static和extern对变量的作用
    【学习笔记】【C语言】static和extern对函数的作用
    【学习笔记】【C语言】typedef
    【学习笔记】【C语言】文件的包含
    【学习笔记】【C语言】条件编译
    【学习笔记】【C语言】宏定义
    【学习笔记】【C语言】枚举
    【学习笔记】【C语言】结构体的嵌套
    【学习笔记】【C语言】结构体和函数
  • 原文地址:https://www.cnblogs.com/whatbeg/p/4002651.html
Copyright © 2011-2022 走看看