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\n",ans[i]);

    }

    return 0;

}
View Code

 

你可能感兴趣的:(HDU)