*题目描述 *
华华看书了解到,一起玩养成类的游戏有助于两人培养感情。所以他决定和月月一起种一棵树。因为华华现在也是信息学高手了,所以他们种的树是信息学意义下的。
华华和月月一起维护了一棵动态有根树,每个点有一个权值。刚开存档的时候,树上只有 0 号节点,权值为 0 。接下来有两种操作:
操作 1:输入格式,表示月月氪金使节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少)。
操作 2:输入格式 ,表示华华上线做任务使节点 i 的子树中所有节点(即它和它的所有子孙节点)权值加 a 。
但是月月有时会检查华华有没有认真维护这棵树,会作出询问:
询问 3:输入格式,华华需要给出 i 节点此时的权值。
华华当然有认真种树了,不过还是希望能写个程序以备不时之需。

输入描述:
第一行一个正整数M,接下来M行,每行先输入一个正整数O表示操作类型,再输入一个非负整数i表示操作或询问的节点编号,如果O=2,再输入一个正整数a。

思路:首先这是一棵树,我们采用离线的做法先将这颗树建好,然后跑一遍dfs序,记录子树大小。针对操作1我们只需要将该点的权值设置为0就行,至于为啥不用修改子孙节点,这是因为子孙节点一定是在当前节点之后才长出的,所以我们只需在下一次操作1修改就行。针对操作2,我们就需要更新该节点以及他的子孙节点了。剩下的操作3就是查询操作了。这里涉及到单点修改,区间修改,单点查询,经典线段树嘛。

代码:

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int a[400005],lazy[400005],siz[400005],vis[400005];
int sum[400005],id=0;
vector<int>edge[400005];
struct Node{
    int op,pos,w;
}b[400005];
int dfs(int u)//跑出dfs序用来跑线段树
{
    vis[u]=++id;//记录该节点的访问时间即时间戳
    for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i];
        siz[u]+=dfs(v);
    }
    return siz[u]+1;//子树大小不包括自己,方便在dfs序中更新子孙节点
}
void pushdown(int p)//线段树向下更新
{
    if(lazy[p]){
        lazy[p*2]+=lazy[p];
        lazy[p*2+1]+=lazy[p];
        sum[p*2]+=lazy[p];
        sum[p*2+1]+=lazy[p];
        lazy[p]=0;
    }
}
void updateone(int p,int l,int r,int pos)//单点修改
{
    if(l==r){
        sum[p]=0;
        return;
    }
    pushdown(p);
    int mid=(l+r)/2;
    if(pos<=mid)updateone(p*2,l,mid,pos);
    else updateone(p*2+1,mid+1,r,pos);
}
void updatemul(int p,int l,int r,int ul,int ur,int w)//区间修改
{
    if(ul<=l&&ur>=r){
        sum[p]+=w;
        lazy[p]+=w;

        return ;
    }
    pushdown(p);
    int mid=(l+r)/2;
    if(ul<=mid)updatemul(p*2,l,mid,ul,ur,w);
    if(ur>mid)updatemul(p*2+1,mid+1,r,ul,ur,w);
}
int query(int p,int l,int r,int pos)//单点查询
{
    if(l==r){
        return sum[p];
    }
    pushdown(p);
    //printf("%d %d %d\n",l,r,sum[p]);
    int mid=(l+r)/2;
    if(pos<=mid)return query(p*2,l,mid,pos);
    else return query(p*2+1,mid+1,r,pos);
}
int main()
{
    int M;
    scanf("%d",&M);
    int n=0;
    for(int i=0;i<M;i++){
        int op,pos,w;
        scanf("%d",&op);
        b[i].op=op;
        if(op==1){
            scanf("%d",&pos);
            b[i].pos=pos;
            n++;
            edge[pos].push_back(n);
        }else if(op==2){
            scanf("%d%d",&pos,&w);
            b[i].pos=pos,b[i].w=w;
        }else{
            scanf("%d",&pos);
            b[i].pos=pos;
        }
    }
    dfs(0);
    n=0;
    for(int i=0;i<M;i++){
        if(b[i].op==1){
            updateone(1,1,id,vis[++n]);
        }else if(b[i].op==2){
            updatemul(1,1,id,vis[b[i].pos],vis[b[i].pos]+siz[b[i].pos],b[i].w);
        }else {
            printf("%d\n",query(1,1,id,vis[b[i].pos]));
        }
    }
    return 0;
}