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


    Aragorn's Story

    来源:http://www.fjutacm.com/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
    ", 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
    ", tree.ALL(id[x])+sav[x]);
            }
        }
        return 0;
    }
    树链剖分+树状数组
  • 相关阅读:
    边工作边刷题:70天一遍leetcode: day 11-1
    边工作边刷题:70天一遍leetcode: day 11
    边工作边刷题:70天一遍leetcode: day 12-1
    边工作边刷题:70天一遍leetcode: day 12
    边工作边刷题:70天一遍leetcode: day 13-1
    边工作边刷题:70天一遍leetcode: day 13-2
    边工作边刷题:70天一遍leetcode: day 13
    边工作边刷题:70天一遍leetcode: day 14-1
    边工作边刷题:70天一遍leetcode: day 14
    边工作边刷题:70天一遍leetcode: day 15
  • 原文地址:https://www.cnblogs.com/DCD112358/p/8847173.html
Copyright © 2020-2023  润新知