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

Posted lalalatianlalu

tags:

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

题意:给你一棵树,然后有三种操作

  I L R K: 把L与R的路径上的所有点权值加上K

  D L R K:把L与R的路径上的所有点权值减去K

  Q X:查询节点编号为X的权值

思路:树链剖分裸题(我还没有怎么学懂,但基本已经没有什么太大的问题,主要的问题就在于点或者边对于数据结构的映射关系是,主要没有单独手写过树链剖分,所以对这部分 没有什么体会)

我们知道树链剖分是一种将树剖为链的一种算法,其思想和dfs序差不多,但根据树链剖分的性质,我们的重链是连续的区间,这样对于重链或者重链上的点我们可以方便的用数据结构维护,对于修改操作,是一种类似于LCA的算法,但感觉本质上还是一种LCA,只不过每次向上跳的部分是跳到top,其他的就是两次dfs,分别维护组时候大小以及一些其他的东西,第二遍dfs 找出重链

代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn=50008;
const int maxm=100008;

int n,m,Q;
int a[maxn],sz[maxn],dep[maxn],fa[maxn],top[maxn],w[maxn],son[maxn];
int Rank[maxn];
int sum[maxn<<2],lazy[maxn<<2];

struct line
{
    int u,v,nxt;
}eg[maxm];
int head[maxn],summ,cnt;
void addedge(int u,int v)
{
    eg[++summ].u=u;
    eg[summ].v=v;
    eg[summ].nxt=head[u];
    head[u]=summ;
}
void add(int u,int v)
{
    addedge(u,v);addedge(v,u);
}
void dfs1(int u)
{
    sz[u]=1;son[u]=0;
    for(int i=head[u];i;i=eg[i].nxt){
        int v=eg[i].v;
        if(v!=fa[u]){
            fa[v]=u;
            dep[v]=dep[u]+1;
            dfs1(v);
            sz[u]+=sz[v];
            if(sz[v]>sz[son[u]])son[u]=v;
        }
    }
}

void dfs2(int u,int tp,int x)
{
    top[u]=tp;w[u]=++cnt;Rank[cnt]=u;
    if(son[u])dfs2(son[u],tp,1);
    for(int i=head[u];i;i=eg[i].nxt){
        int v=eg[i].v;
        if(v==son[u]||v==fa[u])continue;
        dfs2(v,v,2);
    }
}

void init()
{
    memset(head,0,sizeof(head));
    summ=1;cnt=0;
    dep[1]=1;fa[1]=0;
}
void pushup(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int len)
{
    if(lazy[rt]){
        lazy[rt<<1]+=lazy[rt];
        lazy[rt<<1|1]+=lazy[rt];
        sum[rt<<1]+=lazy[rt]*(len-len/2);
        sum[rt<<1|1]+=lazy[rt]*(len/2);
        lazy[rt]=0;
    }
}

void build(int l,int r,int rt)
{
    lazy[rt]=0;
    if(l==r){
        sum[rt]=a[Rank[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,rt<<1);
    build(mid+1,r,rt<<1|1);
    pushup(rt);
}
void update(int L,int R,int val,int l,int r,int rt)
{
    if(L<=l&&r<=R){
        sum[rt]+=val*(r-l+1);
        lazy[rt]+=val;
        return ;
    }
    pushdown(rt,r-l+1);
    int mid=(l+r)>>1;
    if(L<=mid)update(L,R,val,l,mid,rt<<1);
    if(mid<R)update(L,R,val,mid+1,r,rt<<1|1);
    pushup(rt);
}

int query(int x,int l,int r,int rt)
{
    if(l==r){
        return sum[rt];
    }
    pushdown(rt,r-l+1);
    int mid=(l+r)>>1;
    if(x<=mid)return query(x,l,mid,rt<<1);
    if(mid<x)return query(x,mid+1,r,rt<<1|1);
}
void modify(int x,int y,int val)
{
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        update(w[top[x]],w[x],val,1,n,1);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y])swap(x,y);
    update(w[x],w[y],val,1,n,1);
}

int main()
{
    while(~scanf("%d%d%d",&n,&m,&Q)){
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=m;i++){
            int u,v;
            scanf("%d%d",&u,&v);
            add(u,v);
        }
        dfs1(1);
        dfs2(1,1,1);
        build(1,cnt,1);
        while (Q--){
            char s[2];
            int x,y,z;
            scanf("%s",s);
            if (s[0]==I){
                scanf("%d %d %d",&x,&y,&z);
                modify(x,y,z);
            }
            if (s[0]==D){
                scanf("%d %d %d",&x,&y,&z);
                modify(x,y,-z);
            }
            if (s[0]==Q){
                scanf("%d",&x);
                printf("%d
",query(w[x],1,n,1));
            }
        }
    }
    return 0;
}

 

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

hdu 3966 Aragorn's Story

AC日记——Aragorn's Story HDU 3966

HDU 3966 Aragorn's Story

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

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

HDU 3966 Aragorn's Story 树链剖分+BIT区间修改/单点询问