洛谷 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

题解:
  树链剖分的板子好久没打了,写一写。
 
代码:
  
// luogu-judger-enable-o2
// luogu-judger-enable-o2
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#define MAXN 400100
#define ll long long
using namespace std;
struct edge{
    int first;
    int next;
    int to;
}a[MAXN*2];
struct tree{
    int l,r;ll sum,lz; 
}tr[MAXN*4];

int num,n;
int dep[MAXN],sz[MAXN],id[MAXN],son[MAXN],tp[MAXN],dfn[MAXN],las[MAXN],fa[MAXN];

void addedge(int from,int to){
    a[++num].to=to;
    a[num].next=a[from].first;
    a[from].first=num;
}

void dfs1(int now,int f){
    fa[now]=f,sz[now]=1,dep[now]=dep[f]+1;
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==f) continue;
        dfs1(to,now);
        sz[now]+=sz[to];
        if(sz[son[now]]<sz[to]) son[now]=to;
    }
}

void dfs2(int now,int top){
    dfn[now]=++num;
    tp[now]=top;
    if(son[now]) dfs2(son[now],top);
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;if(to==fa[now]||to==son[now]) continue;
        dfs2(to,to);
    }
    las[now]=num;
}

void pushdown(int xv){
    int ls=2*xv,rs=2*xv+1;
    if(tr[xv].lz){
        tr[ls].sum+=(tr[ls].r-tr[ls].l+1)*tr[xv].lz;
        tr[rs].sum+=(tr[rs].r-tr[rs].l+1)*tr[xv].lz;
        tr[ls].lz+=tr[xv].lz,tr[rs].lz+=tr[xv].lz;
        tr[xv].lz=0;
    }
}

void pushup(int xv){
    tr[xv].sum=tr[xv*2].sum+tr[xv*2+1].sum;
}

void build(int xv,int l,int r){
    if(l==r){
        tr[xv].l=l,tr[xv].r=r,tr[xv].sum=0,tr[xv].lz=0;
        return;
    }
    tr[xv].l=l,tr[xv].r=r,tr[xv].sum=0,tr[xv].lz=0;
    int mid=(l+r)/2;
    build(xv*2,l,mid),build(xv*2+1,mid+1,r);
}

void modify(int xv,int l,int r,int z){
    int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2;
    if(L==l&&R==r){
        tr[xv].sum+=z*(R-L+1);
        tr[xv].lz+=z;
        return;
    }
    pushdown(xv);
    if(r<=mid) modify(xv*2,l,r,z);
    else if(l>mid) modify(xv*2+1,l,r,z);
    else modify(xv*2,l,mid,z),modify(xv*2+1,mid+1,r,z);
    pushup(xv);
}

ll query(int xv,int l,int r){
    int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2;
    if(L==l&&R==r) return tr[xv].sum;
    pushdown(xv);
    if(r<=mid) return query(xv*2,l,r);
    else if(l>mid) return query(xv*2+1,l,r);
    else return query(xv*2,l,mid)+query(xv*2+1,mid+1,r);
}

void add(int x,int y,int z){
    int topx=tp[x],topy=tp[y];
    while(topx!=topy){
        if(dep[topx]<dep[topy]) swap(x,y),swap(topx,topy);
        modify(1,dfn[topx],dfn[x],z);
        x=fa[topx];topx=tp[x];
    }
    if(dep[x]<dep[y]) swap(x,y);
    modify(1,dfn[y],dfn[x],z);
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int x,y;scanf("%d%d",&x,&y);
        x++,y++;
        addedge(x,y),addedge(y,x);
    }
    dfs1(1,0);num=0;
    dfs2(1,1);fa[1]=1;
    build(1,1,n);
    int q;cin>>q;
    while(q--){
        char id;cin>>id;
        if(id=='A'){
            int x,y,z;scanf("%d%d%d",&x,&y,&z);x++,y++;
            add(x,y,z);
        }
        else{
            int x;scanf("%d",&x);x++;
            printf("%lld\n",query(1,dfn[x],las[x]));
        }
    }
    return 0;
}

 

posted @ 2018-08-20 19:44  人间失格—太宰治  阅读(160)  评论(0编辑  收藏  举报