洛谷——P3833 [SHOI2012]魔法树

P3833 [SHOI2012]魔法树

题目背景

SHOI2012 D2T3

题目描述

Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。

这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。

不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:

Add u v d

表示将点u和v之间的路径上的所有节点的果子个数都加上d。

接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:

Query u

表示当前果树中,以点u为根的子树中,总共有多少个果子?

输入输出格式

输入格式:

第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。

接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。

接下来是一个正整数Q(1 ≤ ? ≤ 100000),表示共有Q次操作。

后面跟着Q行,每行是以下两种中的一种:

  1. A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000

  2. Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。

输出格式:

对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。

输入输出样例

输入样例#1: 复制
4
0 1
1 2
2 3
4
A 1 3 1
Q 0
Q 1
Q 2
输出样例#1: 复制
3
3
2

 

树链剖分模板题,注意一下细节即可

#include<bits/stdc++.h>

#define N 1010100
#define LL long long
using namespace std;

struct node {
    LL to,next;
} e[N];
struct tree {
    LL l,r,w,f;
} tr[N];

LL n,m,head[N],tot,ans;

//(u,v)树上修改 
//询问子树大小

void add(LL u,LL v) {
    e[++tot].to=v,e[tot].next=head[u],head[u]=tot;
}

LL dep[N],siz[N],son[N],fa[N];
void dfs(LL u,LL f,LL deep) {
    dep[u]=deep,siz[u]=1,fa[u]=f;
    LL maxson=-1;
    for(LL i=head[u]; i; i=e[i].next) {
        LL v=e[i].to;
        if(v==f) continue;
        dfs(v,u,deep+1);
        siz[u]+=siz[v];
        if(siz[v]>maxson) maxson=siz[v],son[u]=v;
    }
}

LL top[N],id[N],item;
void dfs2(LL u,LL topf) {
    id[u]=++item,top[u]=topf;
    if(!son[u]) return;
    dfs2(son[u],topf);
    for(LL i=head[u]; i; i=e[i].next) {
        LL v=e[i].to;
        if(v==fa[u]||v==son[u]) continue;
        dfs2(v,v);
    }
}

void build(LL k,LL l,LL r) {
    tr[k].l=l,tr[k].r=r;
    if(l==r) return;
    LL mid=(l+r)/2;
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
}

void upda(LL k) {
    tr[k].w=tr[k*2].w+tr[k*2+1].w;
}
void down(LL k) {
    LL f=tr[k].f;
    tr[k].f=0;
    tr[k*2].w=(tr[k*2].w+f*(tr[k*2].r-tr[k*2].l+1));
    tr[k*2+1].w=(tr[k*2+1].w+f*(tr[k*2+1].r-tr[k*2+1].l+1));
    tr[k*2].f+=f,tr[k*2+1].f+=f;
}

void change_LLerval(LL k,LL l,LL r,LL p) {
    LL ll=tr[k].l,rr=tr[k].r,mid=(ll+rr)/2;
    if(ll>=l&&rr<=r) {
        tr[k].w=(tr[k].w+(rr-ll+1)*p);
        tr[k].f+=p;
        return;
    }
    if(tr[k].f) down(k);
    if(l<=mid) change_LLerval(k*2,l,r,p);
    if(r>mid) change_LLerval(k*2+1,l,r,p);
    upda(k);
}

void ask_LLerval(LL k,LL l,LL r) {
    LL ll=tr[k].l,rr=tr[k].r,mid=(ll+rr)/2;
    if(ll>=l&&rr<=r) {
        ans+=tr[k].w;
        return;
    }
    if(tr[k].f) down(k);
    if(l<=mid) ask_LLerval(k*2,l,r);
    if(r>mid) ask_LLerval(k*2+1,l,r);
    upda(k);
}

void change(LL a,LL b,LL p) {
    while(top[a]!=top[b]) {
        if(dep[top[a]]<dep[top[b]]) swap(a,b);
        change_LLerval(1,id[top[a]],id[a],p);
        a=fa[top[a]];
    }
    if(dep[a]<dep[b]) swap(a,b);
    change_LLerval(1,id[b],id[a],p);
}

LL sum(LL a) {
    ans=0;
    ask_LLerval(1,id[a],id[a]+siz[a]-1);
    return ans;
}

int main() {
    scanf("%lld",&n);
    for(LL a,b,i=1; i<n; i++) {
        scanf("%lld%lld",&a,&b);
        add(a+1,b+1);
    }
    dfs(1,0,1);
    dfs2(1,1);
    build(1,1,n);
    scanf("%lld",&m);
    for(LL a,b,c,i=1; i<=m; i++) {
        char x;
        cin>>x;
        if(x=='A') {
            scanf("%lld%lld%lld",&a,&b,&c);
            change(a+1,b+1,c);
        } else {
            scanf("%lld",&a);
            printf("%lld
",sum(a+1));
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/song-/p/9545192.html