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\n",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();
}

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

猜你喜欢

转载自www.cnblogs.com/Tobichi/p/9113112.html