hdu3966(树链剖分+线段树)

Posted shutdown113

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu3966(树链剖分+线段树)相关的知识,希望对你有一定的参考价值。

Aragorn‘s Story

题意:

  给出n个营地初始士兵的数量和n-1条边,保证任意两个营地之间只有一条路径到达。现在有3种操作,如果为I,则u到v路径上的所有营地的士兵个数增加w,为D,则减少w,为Q,输出路径上所有营地的士兵总和。(总和允许为负数)

分析:

  树链剖分的模板题吧,利用树链剖分求出重链,重链上的点可以通过dfs序来转换成一段子区间,利用线段树维护子区间和即可。

  学习博客:大佬博客

代码:

技术分享图片
#include <map>
#include <queue>
#include <math.h>
#include <string>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;
#define ll long long
#define ull unsigned long long
#define cls(x) memset(x,0,sizeof(x))
#define clslow(x) memset(x,-1,sizeof(x))

const int maxn=1e5+100;

int tot;
int n,m,k;

int arr[maxn];
int head[maxn];

struct Edge{
    int v,nex;
};
Edge edge[maxn<<1];

void init()
{
    tot=0;
    clslow(head);
}

void addEdge(int u,int v)
{
    edge[tot].v=v;
    edge[tot].nex=head[u];
    head[u]=tot++;
}

namespace IntervalTree {
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    ll add[maxn<<2],sum[maxn<<2];
    void PushUp(int rt)
    {
        sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    }
    void PushDown(int m,int rt)
    {
        if(add[rt]){
            add[rt<<1]+=add[rt];
            add[rt<<1|1]+=add[rt];
            sum[rt<<1]+=(m-(m>>1))*add[rt];
            sum[rt<<1|1]+=(m>>1)*add[rt];
            add[rt]=0;
        }
    }
    void build(int l,int r,int rt)
    {
        add[rt]=0;
        sum[rt]=0;
        if(l==r)    return;
        int m=(l+r)>>1;
        build(lson);
        build(rson);
        PushUp(rt);
    }
    void update(int L,int R,int c,int l,int r,int rt)
    {
        if(L<=l&&r<=R){
            add[rt]+=c;
            sum[rt]+=c*(r-l+1);
            return;
        }
        PushDown(r-l+1,rt);
        int m=(l+r)>>1;
        if(L<=m)    update(L,R,c,lson);
        if(R>m)     update(L,R,c,rson);
        PushUp(rt);
    }
    ll query(int L,int R,int l,int r,int rt)
    {
        if(L<=l&&r<=R){
            return sum[rt];
        }
        PushDown(r-l+1,rt);
        ll ans=0;
        int m=(l+r)>>1;
        if(L<=m)    ans+=query(L,R,lson);
        if(R>m)     ans+=query(L,R,rson);
        return ans;
    }
}

namespace HLD {
    int cnt;
    int top[maxn<<1],rnk[maxn<<1],dfsid[maxn<<1];
    int sz[maxn<<1],fa[maxn<<1],son[maxn<<1],dep[maxn<<1];
    void init()
    {
        cnt=1;
        cls(sz);
        clslow(son);
        IntervalTree::build(1,n,1);
    }
    void dfs1(int u,int father,int deep)
    {
        sz[u]=1;
        dep[u]=deep;
        fa[u]=father;
        for(int i=head[u];~i;i=edge[i].nex){
            int v=edge[i].v;
            if(v==fa[u])   continue;
            dfs1(v,u,deep+1);
            sz[u]+=sz[v];
            if(son[u]==-1||sz[v]>sz[son[u]]){
                son[u]=v;
            }
        }
    }
    void dfs2(int u,int s)
    {
        top[u]=s;
        dfsid[u]=cnt;
        rnk[cnt++]=u;
        if(son[u]==-1)  return;
        dfs2(son[u],s);
        for(int i=head[u];~i;i=edge[i].nex){
            int v=edge[i].v;
            if(v!=son[u]&&v!=fa[u]){
                dfs2(v,v);
            }
        }
    }
    void update(int x,int y,int z)
    {
        int fx=top[x],fy=top[y];
        while(fx!=fy)
        {
            if(dep[fx]>dep[fy]){
                IntervalTree::update(dfsid[fx],dfsid[x],z,1,n,1);
                x=fa[fx];
            }
            else {
                IntervalTree::update(dfsid[fy],dfsid[y],z,1,n,1);
                y=fa[fy];
            }
            fx=top[x],fy=top[y];
        }
        int L=min(dfsid[x],dfsid[y]);
        int R=max(dfsid[x],dfsid[y]);
        IntervalTree::update(L,R,z,1,n,1);
    }
    ll query(int x,int y)
    {
        ll ans=0;
        int fx=top[x],fy=top[y];
        while(fx!=fy)
        {
            if(dep[fx]>dep[fy]){
                ans+=IntervalTree::query(dfsid[fx],dfsid[x],1,n,1);
                x=fa[fx];
            }
            else {
                ans+=IntervalTree::query(dfsid[fy],dfsid[y],1,n,1);
                y=fa[fy];
            }
            fx=top[x],fy=top[y];
        }
        int L=min(dfsid[x],dfsid[y]);
        int R=max(dfsid[x],dfsid[y]);
        ans+=IntervalTree::query(L,R,1,n,1);
        return ans;
    }
}

int main()
{
    #ifndef ONLINE_JUDGE
        freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    while(scanf("%d %d %d",&n,&m,&k)!=EOF)
    {
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&arr[i]);
        }
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d %d",&u,&v);
            addEdge(u,v);addEdge(v,u);
        }

        HLD::init();
        HLD::dfs1(1,-1,1);
        HLD::dfs2(1,1);
        for(int i=1;i<=n;i++){
            HLD::update(i,i,arr[i]);
        }

        for(int i=1;i<=k;i++){
            char op;
            int x,y,z;
            scanf("%s",&op);
            if(op==Q){
                scanf("%d",&x);
                printf("%I64d
",HLD::query(x,x));
            }
            else if(op==I){
                scanf("%d %d %d",&x,&y,&z);
                HLD::update(x,y,z);
            }
            else if(op==D){
                scanf("%d %d %d",&x,&y,&z);
                HLD::update(x,y,-z);
            }
        }
    }
    return 0;
}
View Code

 

以上是关于hdu3966(树链剖分+线段树)的主要内容,如果未能解决你的问题,请参考以下文章

HDU - 3966 Aragorn's Story(树链剖分入门+线段树)

HDU 3966 Aragorn's Story (树链剖分+线段树)

HDU-3966 Aragorn's Story(树链剖分+线段树)

HDU 3966 Aragorn's Story(模板题)树链剖分+线段树

Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组

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