#30 [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

思维难度:NOIP+

代码难度:省选

算法:树链剖分

#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
const int Maxn=100005;
ll fa[Maxn],sz[Maxn],son[Maxn],idx[Maxn],deep[Maxn],top[Maxn],h[Maxn],tcnt,cnt,root;
ll n,m; 
struct node{
    ll v,next;
}e[Maxn*2];
struct tree{
    ll x,l,r,c;
}t[Maxn*4];
inline ll dfs1(ll u){
    sz[u]=1;
    ll heavy=0,maxn=0;
    for(ll i=h[u];i;i=e[i].next){
        ll v=e[i].v;
        deep[v]=deep[u]+1;
        fa[v]=u;
        ll tmp=dfs1(v);
        if(maxn<tmp){
            maxn=tmp;
            heavy=v;
        }
        sz[u]+=tmp;
    }
    son[u]=heavy;
    return sz[u];
}
inline void dfs2(ll u){
    idx[u]=++tcnt;
    if(!son[u])return;
    top[son[u]]=top[u];dfs2(son[u]);
    for(ll i=h[u];i;i=e[i].next){
        ll v=e[i].v;
        if(son[u]==v)continue;
        top[v]=v;
        dfs2(v);
    }
}
inline ll lson(ll rt){
    return rt<<1;
}
inline ll rson(ll rt){
    return rt<<1|1; 
}
inline void pushup(ll rt){
    t[rt].x=t[lson(rt)].x+t[rson(rt)].x;
}
inline void build(ll l,ll r,ll rt){
    t[rt].l=l;t[rt].r=r;
    if(l==r)return;
    ll mid=l+r>>1;
    build(l,mid,lson(rt));
    build(mid+1,r,rson(rt));
}
inline void pushdown(ll rt){
    if(t[rt].l==t[rt].r)return;
    if(t[rt].c==0)return;
    t[lson(rt)].c+=t[rt].c;
    t[rson(rt)].c+=t[rt].c;
    t[lson(rt)].x+=t[rt].c*(t[lson(rt)].r-t[lson(rt)].l+1);
    t[rson(rt)].x+=t[rt].c*(t[rson(rt)].r-t[rson(rt)].l+1);
    t[rt].c=0;
}
inline void update(ll l,ll r,ll x,ll rt){
    if(t[rt].l>=l&&t[rt].r<=r){
        t[rt].x+=x*(t[rt].r-t[rt].l+1);
        t[rt].c+=x;
        return;
    }
    pushdown(rt);
    ll mid=t[rt].l+t[rt].r>>1;
    if(l<=mid){
        update(l,r,x,lson(rt));
    }
    if(r>mid){
        update(l,r,x,rson(rt));
    } 
    pushup(rt);
}
inline ll query(ll l,ll r,ll rt){
    if(t[rt].l>=l&&t[rt].r<=r){
        return t[rt].x;
    }
    pushdown(rt);
    ll mid=t[rt].l+t[rt].r>>1,ans=0;
    if(l<=mid){
        ans+=query(l,r,lson(rt));
    }
    if(r>mid){
        ans+=query(l,r,rson(rt));
    }
    return ans;
}
inline void Tupdate(ll x,ll y,ll val){
    while(top[x]!=top[y]){
        if(deep[top[x]]<deep[top[y]])swap(x,y);
        update(idx[top[x]],idx[x],val,1);
        x=fa[top[x]];
    }
    if(idx[x]>idx[y])swap(x,y);update(idx[x],idx[y],val,1);
}
inline char getc(){
    char c=getchar();
    while(c!='A'&&c!='Q')c=getchar();
    return c;
}
inline ll read(){
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9'){
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
inline void add(ll u,ll v){
    cnt++;
    e[cnt].v=v;
    e[cnt].next=h[u];
    h[u]=cnt;
}
int main(){
    int u,v,w;char inc;n=read();
    for(int i=1;i<=n-1;i++){
        u=read();v=read();
        add(u,v);
    }
    dfs1(root);dfs2(root);build(1,n,1);
    m=read();
    for(int i=1;i<=m;i++){
        inc=getc();u=read();
        if(inc=='A'){
            v=read();w=read();
            Tupdate(u,v,w);
        }
        else{
            printf("%lld\n",query(idx[u],idx[u]+sz[u]-1,1));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LvYanchang/article/details/81635384
今日推荐