• BZOJ 2836: 魔法树 树链剖分


    2836: 魔法树

    Description

    Input

    Output

    Sample Input

    4
    0 1
    1 2
    2 3
    4
    Add 1 3 1
    Query 0
    Query 1
    Query 2

    Sample Output

    3
    3
    2

    思路:

      树链剖分线段树裸题。值得注意的是维护一下出栈序,这样子树就是该点到出栈+1的位置。在LCA的过程中直接查询/维护即可

    下面是代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cctype>
    #define ls p<<1
    #define rs ls|1
    #define lson l,mid,ls
    #define rson mid+1,r,rs
    #define im int mid = (l + r) >> 1
    using namespace std;
    const int N = 1100000;
    int son[N],siz[N],fa[N],top[N],dep[N];
    int idx[N],cnt2;
    int to[N<<1],next[N<<1],head[N],cnt1;
    int sec[N<<1];
    int n,m;
    class ReadIn {
        private:
        inline char nc() {
            static char buf[100000], *p1, *p2;
            return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
        }
        public:
        inline int read() {
            int x=0;char ch=nc();
            while(!isdigit(ch))ch=nc();
            while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=nc();}
            return x;
        }
        inline char getc() {
            char ch=nc();
            while(isspace(ch))ch=nc();
            return ch;
        }
    }Rd;
    class SegmentTree {
        #define int long long
        private:
        int sum[N<<2],laz[N<<2];
        void pushdown(int l,int r,int p,int c) {
            sum[p]+=(r-l+1)*c;
            laz[p]+=c;
        }
        public:
        int query(int l,int r,int p,int x,int y) {
            if(x<=l&&y>=r) {
                return sum[p];
            }
            im;
            if(laz[p])
            {
                pushdown(l,mid,ls,laz[p]);
                pushdown(mid+1,r,rs,laz[p]);
                laz[p]=0;
            }
            int re=0;
            if(x<=mid)
                re+= query(lson,x,y);
            if(y>mid)
                re+= query(rson,x,y);
            return re;
        }
        void change(int l,int r,int p,int x,int y,int c) {
            if(x<=l&&y>=r) {
                laz[p]+=c;
                sum[p]+=c*(r-l+1);
                return;
            }
            im;
            if(laz[p])
            {
                pushdown(l,mid,ls,laz[p]);
                pushdown(mid+1,r,rs,laz[p]);
                laz[p]=0;
            }
            if(x<=mid)
                change(lson,x,y,c);
            if(y>mid)
                change(rson,x,y,c);
            sum[p]=sum[ls]+sum[rs];
        }
    }Tr;
    class TreeChainDissection {
        public:
        void dfs1(int p) {
            dep[p]=dep[fa[p]]+1;
            siz[p]=1;
            for (int i = head[p];i; i = next[i] ) {
                if(to[i] != fa[p]) {
                    fa[to[i]]=p;
                    dfs1(to[i]);
                    siz[p]+=siz[to[i]];
                    if(siz[to[i]]>siz[son[p]])
                        son[p]=to[i];
                }
            }
        }
        void dfs2(int p,int t) {
            idx[p]=++cnt2;
            top[p]=t;
            if(son[p]) dfs2(son[p],t);
            for(int i=head[p];i;i=next[i])
                if(to[i]!=fa[p]&&to[i]!=son[p])
                    dfs2(to[i],to[i]);
            sec[p] = cnt2;
        }
        void lcac(int x,int y,int z) {
            while(top[x]!=top[y])
            {
                if(dep[top[x]]>dep[top[y]])swap(x,y);
                Tr.change(1,n,1,idx[top[y]],idx[y],z);
                y=fa[top[y]];
            }
            if(dep[x]<dep[y])swap(x,y);
            Tr.change(1,n,1,idx[y],idx[x],z);
        }
     
    }Tcd;
    class Pre {
        private:
        inline void add_edge(int a,int b) {
            to[++cnt1] = b;
            next[cnt1] = head[a];
            head[a] = cnt1;
     
            to[++cnt1] = a;
            next[cnt1] = head[b];
            head[b] = cnt1;
        }
        public:
        void init() {
            n=Rd.read();
            int i,x,y;
            for(i=1 ;i < n; i++) {
                x=Rd.read(),y=Rd.read();
                add_edge(x+1,y+1);
            }
            m=Rd.read();
        }
    }Pr;
    void solve() {
        Tcd.dfs1(1);
        Tcd.dfs2(1,1);
        //Tr.build(1,n,1);
        int i,x,y,z;
        char opt;
        for(i=1;i<=m;i++) {
            opt=Rd.getc();
            if(opt=='Q') {
                x=Rd.read();
                x++;
                int ans = Tr.query(1,n,1,idx[x],sec[x]);
                printf("%lld
    ",ans);
            }
            else {
                x=Rd.read(), y=Rd.read(), z=Rd.read();
                Tcd.lcac(x+1,y+1,z);
            }
        }
    }
    #undef int
    int main() {
        Pr.init();
        solve();
    }
    

     欢迎来原博客看看 >原文链接<

  • 相关阅读:
    Thinkphp 边学边用验证码无意间犯的错
    如何计算团队成员贡献分
    禅道使用之项目经理篇
    禅道使用之开发团队篇
    黑盒测试实践作业进度报告(周日)
    黑盒测试实践作业进度报告(周六)
    禅道使用之产品经理篇
    第1周小组博客作业——关于禅道测试管理的总结
    禅道介绍与环境搭建
    一个工作了5年的程序员,将来在哪里?
  • 原文地址:https://www.cnblogs.com/Tobichi/p/9113112.html
Copyright © 2020-2023  润新知