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

Posted DCD暗夜殇

tags:

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

Aragorn‘s Story

来源:http://120.78.128.11/Problem.jsp?pid=2710 来源:http://acm.hdu.edu.cn/showproblem.php?pid=3966

这题就是一个模板题,模板调过了就可以过

技术分享图片
#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define mid ((node[now].l+node[now].r)>>1)
#define lson node[now].l, mid, now<<1
#define rson mid+1, node[now].r, now<<1^1
#define Q(A, B) memset(A, B, sizeof(A))
using namespace std;
const int N=50505;
const int INF=0x3f3f3f3f;
typedef int mint;
mint fa[N], siz[N], dep[N], son[N];
mint id[N], top[N], self[N], cnt;
/**
siz[u]    保存以u为根的子树节点个数
top[u]    保存当前节点所在链的顶端节点
son[u]    保存重儿子
dep[u]    保存结点u的深度值
fa[u]    保存结点u的父亲节点
id[u]    保存树中每个节点剖分以后的新编号(DFS的执行顺序)
self[u]    保存当前节点在树中的位置
**/
mint sz, head[N];
mint sav[N];
mint n, mod;
void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<0|s>9){if(s==-)f=-1;s=getchar();}
    while(s>=0&&s<=9){x=x*10+s-0;s=getchar();}
    x*=f;
}
mint Max(mint a, mint b)
{ return a>b?a:b; }
mint Min(mint a, mint b)
{ return a<b?a:b; }

struct Ed
{
    int to, next;
}E[N*2];

void insert_E(int u, int v)
{
    E[sz].to=v;
    E[sz].next=head[u];
    head[u]=sz++;
}
struct No
{
    mint ret;
    struct no
    {
        mint l, r, sum, mins, maxn, lazy, lazyset;
    }node[N<<2];
    void build(int L, int R, int now)///建树
    {
        node[now].lazy=0;
        node[now].lazyset=0;
        node[now].l=L;
        node[now].r=R;
        if(L==R)
            node[now].mins=node[now].maxn=node[now].sum=self[L];
        else
        {
            build(L, mid, now<<1);
            build(mid+1, R, now<<1^1);
            pushup(now);
        }
    }
    void pushup(int now)
    {
        node[now].sum=node[now<<1].sum+node[now<<1^1].sum;
        node[now].maxn=Max(node[now<<1].maxn, node[now<<1^1].maxn);
        node[now].mins=Min(node[now<<1].mins, node[now<<1^1].mins);
    }
    void pushdown(int now)
    {
        if (node[now].lazy)
        {
            int len=node[now].r-node[now].l+1;
            node[now<<1].lazy+=node[now].lazy;
            node[now<<1^1].lazy+=node[now].lazy;
            node[now<<1].sum+=node[now].lazy*(len-(len>>1));
            node[now<<1^1].sum+=node[now].lazy*(len>>1);
            node[now<<1].maxn+=node[now].lazy;
            node[now<<1^1].maxn+=node[now].lazy;
            node[now<<1].mins+=node[now].lazy;
            node[now<<1^1].mins+=node[now].lazy;
            node[now].lazy=0;
        }
    }
    void pushdown_set(int now)
    {
        if (node[now].lazyset)
        {
            int len=node[now].r-node[now].l+1;
            node[now<<1].lazyset=node[now].lazyset;
            node[now<<1^1].lazyset=node[now].lazyset;
            node[now<<1].sum=node[now].lazyset*(len-(len>>1));
            node[now<<1^1].sum=node[now].lazyset*(len>>1);
            node[now<<1].maxn=node[now].lazyset;
            node[now<<1^1].maxn=node[now].lazyset;
            node[now<<1].mins=node[now].lazyset;
            node[now<<1^1].mins=node[now].lazyset;
            node[now].lazyset=0;
        }
    }
    void update(int L, int R, mint v, int now)///区间更新
    {
        if(L<=node[now].l&&node[now].r<=R)
        {
            node[now].lazy+=v;
            node[now].sum+=(node[now].r-node[now].l+1)*v;
            node[now].maxn+=v;
            node[now].mins+=v;
            return ;
        }
        pushdown(now);
        if(L<=mid)
            update(L, R, v, now<<1);
        if(R>mid)
            update(L, R, v, now<<1^1);
        pushup(now);
    }
    mint query(int L, int R, int now)///区间求和
    {
        if(L<=node[now].l&&R>=node[now].r)
            return node[now].sum;
        pushdown(now);
        mint ret=0;
        if(L<=mid)
            ret+=query(L, R, now<<1);
        if(R>mid)
            ret+=query(L, R, now<<1^1);
        return ret;
    }

    void addn(int now)///将1~n的节点里的值保存到一个sav[]数组里
    {
        for(mint i=node[now].l; i<=node[now].r; i++)
            sav[i]+=node[now].sum;
        if(node[now].l==node[now].r)
            return;
        addn(now<<1);
        addn(now<<1^1);
    }

    mint querymin(int L,int R,int now)///L~R的最小值
    {
        if(L<=node[now].l&&R>=node[now].r)
            return node[now].mins;
        pushdown(now);
        if(L<=mid)
            ret=Min(ret, querymin(L,R,now<<1));
        if(R>mid)
            ret=Min(ret, querymin(L,R,now<<1^1));
        return ret;
    }

    mint querymax(int L,int R,int now)///L~R的最大值
    {
        if(L<=node[now].l&&R>=node[now].r)
            return node[now].maxn;
        pushdown(now);
        if(L<=mid)
            ret=Max(ret, querymax(L,R,now<<1));
        if(R>mid)
            ret=Max(ret, querymax(L,R,now<<1^1));
        return ret;
    }

    void print(int now)///输出所有叶子节点
    {
        if(node[now].l==node[now].r)
            printf("%lld ", node[now].sum);
        else
        {
            print(now<<1);
            print(now<<1^1);
        }
    }
    mint getsum(int x, int y)///表示求树从x到y结点最短路径上所有节点的值之和
    {
        mint ans=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])
                swap(x,y);///把x点改为所在链顶端的深度更深的那个点
            ans+=query(id[top[x]], id[x], 1);///一条链一条链的求和
            x=fa[top[x]];///往高处跑
        }
        if(dep[x]>dep[y])
            swap(x, y);
        return ans+query(id[x], id[y], 1);
    }
    void updrag(int x, int y, mint k)///同上写法///表示将树从x到y结点最短路径上所有节点的值都加上k
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])
                swap(x,y);
            update(id[top[x]], id[x], k, 1);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])
            swap(x, y);
        update(id[x], id[y], k, 1);
    }
    mint qson(int x)///表示求以x为根节点的子树内所有节点值之和
    {
        ret=0;
        query(id[x], id[x]+siz[x]-1, 1);///他有siz[x]-1个子节点;
        return ret;
    }
    void updson(int x, int k)///表示将以x为根节点的子树内所有节点值都加上k
    {
        update(id[x], id[x]+siz[x]-1, k, 1);
    }
}tree;

void init()
{
    Q(head, -1);
    Q(son, 0);
    sz=1;
    cnt=0;
}

void DFS(int now, int DEP, int F)
{
    fa[now]=F;
    dep[now]=DEP;
    siz[now]=1;
    int key=-1;
    for(int i=head[now]; ~i; i=E[i].next)
    {
        if(E[i].to==F)
            continue;
        DFS(E[i].to, DEP+1, now);
        siz[now]+=siz[E[i].to];
        if(siz[E[i].to]>key)
            son[now]=E[i].to, key=siz[E[i].to];
    }
}

void DFS_(mint now, mint tp)
{
    id[now]=++cnt;
    self[cnt]=sav[now];///这个点是build线段树用的
    top[now]=tp;///按序将边加入线段树
    if(!son[now])
        return ;
    DFS_(son[now], tp);///重儿子的top[]从重链顶端继承
    for(int i=head[now]; ~i; i=E[i].next)
    {
        if(E[i].to==son[now]||E[i].to==fa[now])
            continue;
        DFS_(E[i].to, E[i].to);///轻儿子top[]为自身
    }
}
int main()
{
    mint m, r;
    while(~scanf("%d%d%d", &n, &m, &r))
    {
        init();
        for(int i=1; i<=n; i++)
            read(sav[i]);
        while(m--)
        {
            int a, b;
            read(a), read(b);
            insert_E(a, b);
            insert_E(b, a);
        }
        DFS(1, 1, 0);
        DFS_(1, 1);
        tree.build(1, n, 1);
        while(r--)
        {
            char op[33];
            int x, y, z;
            scanf("%s", op);
            read(x);
            if(op[0]==I)
                read(y), read(z), tree.updrag(x, y, z);
            else if(op[0]==D)
                read(y), read(z), tree.updrag(x, y, -z);
            else
                printf("%d\n", tree.getsum(x, x));
        }
    }
    return 0;
}
树链剖分+线段树
技术分享图片
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define Q(A, B) memset(A, B, sizeof(A))
using namespace std;
const int N=50005;
int fa[N], siz[N], dep[N], son[N];
int id[N], top[N], self[N], cnt;
int sz, head[N];
int sav[N];
int n;
void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<0|s>9){if(s==-)f=-1;s=getchar();}
    while(s>=0&&s<=9){x=x*10+s-0;s=getchar();}
    x*=f;
}

struct Ed
{
    int to, next;
}E[N*2];

void insert_E(int u, int v)
{
    E[sz].to=v;
    E[sz].next=head[u];
    head[u]=sz++;
}

struct SZSZ_tree
{
    int sum[N];
    void init()
    {
        Q(sum, 0);
    }
    int lowbit(int x)
    {
        return x&(-x);
    }
    void update(int i, int v)
    {
        while(i<=n)
        {
            sum[i]+=v;
            i+=lowbit(i);
        }
    }
    int ALL(int i)
    {
        int res=0;
        while(i>0)
        {
            res+=sum[i];
            i-=lowbit(i);
        }
        return res;
    }
    void updrag(int x, int y, int k)///同上写法///表示将树从x到y结点最短路径上所有节点的值都加上k
    {
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]])
                swap(x,y);
            update(id[top[x]], k);
            update(id[x]+1, -k);
            x=fa[top[x]];
        }
        if(dep[x]>dep[y])
            swap(x, y);
        update(id[x], k);
        update(id[y]+1, -k);
    }
}tree;

void init()
{
    Q(head, -1);
    Q(son, 0);
    tree.init();
    sz=1;
    cnt=0;
}
void DFS(int now, int DEP, int F)
{
    fa[now]=F;
    dep[now]=DEP;
    siz[now]=1;
    int key=-1;
    for(int i=head[now]; ~i; i=E[i].next)
    {
        if(E[i].to==F)
            continue;
        DFS(E[i].to, DEP+1, now);
        siz[now]+=siz[E[i].to];
        if(siz[E[i].to]>key)
            son[now]=E[i].to, key=siz[E[i].to];
    }
}
void DFS_(int now, int tp)
{
    id[now]=++cnt;
    self[cnt]=sav[now];///这个点是build线段树用的
    top[now]=tp;///按序将边加入线段树
    if(!son[now])
        return ;
    DFS_(son[now], tp);///重儿子的top[]从重链顶端继承
    for(int i=head[now]; ~i; i=E[i].next)
    {
        if(E[i].to==son[now]||E[i].to==fa[now])
            continue;
        DFS_(E[i].to, E[i].to);///轻儿子top[]为自身
    }
}
int main()
{
    int m, r;
    while(~scanf("%d%d%d", &n, &m, &r))
    {
        init();
        for(int i=1; i<=n; i++)
            read(sav[i]), tree.sum[i]=0;
        while(m--)
        {
            int a, b;
            read(a), read(b);
            insert_E(a, b);
            insert_E(b, a);
        }
        DFS(1, 1, 0);
        DFS_(1, 1);
        while(r--)
        {
            char op[33];
            int x, y, z;
            scanf("%s", op);
            read(x);
            if(op[0]==I)
                read(y), read(z), tree.updrag(x, y, z);
            else if(op[0]==D)
                read(y), read(z), tree.updrag(x, y, -z);
            else
                printf("%d\n", tree.ALL(id[x])+sav[x]);
        }
    }
    return 0;
}
树链剖分+树状数组

 

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

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

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

HDU Aragorn's Story -树链剖分

hdu-3966 Aragorn's Story 树链剖分

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

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