三部曲

来源:互联网 发布:淘宝批发在哪里进货 编辑:程序博客网 时间:2024/06/10 13:16

题目大意

对一颗n个节点的树操作。
有两种操作,第一种是对子树j,j的点权+k,j的儿子们点权+k+1,j的孙子们点权+k+2,以此类推。
第二种操作询问子树点权和。

线段树

修改操作实际上是对子树每个点i加上k-d[j]+d[i]
标记可以写成(a,b)表示一个点权为x的点i经过后变成x+a+d[i]*b
显然这个标记可合并而且容易求和。
线段树维护即可。

#include<cstdio>#include<algorithm>#include<cmath>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=50000+10;ll tree[maxn*4],sum[maxn*4],a[maxn*4],b[maxn*4];int h[maxn],go[maxn],nxt[maxn],d[maxn],dfn[maxn],nfd[maxn],size[maxn];int i,j,k,l,t,n,m,tot,top;char ch;int read(){    int x=0,f=1;    char ch=getchar();    while (ch<'0'||ch>'9'){        if (ch=='-') f=-1;        ch=getchar();    }    while (ch>='0'&&ch<='9'){        x=x*10+ch-'0';        ch=getchar();    }    return x*f;}void add(int x,int y){    go[++tot]=y;    nxt[tot]=h[x];    h[x]=tot;}void dfs(int x){    dfn[x]=++top;    nfd[top]=x;    int t=h[x];    size[x]=1;    while (t){        d[go[t]]=d[x]+1;        dfs(go[t]);        size[x]+=size[go[t]];        t=nxt[t];    }}void build(int p,int l,int r){    a[p]=b[p]=0;    if (l==r){        sum[p]=d[nfd[l]];        tree[p]=0;        return;    }    int mid=(l+r)/2;    build(p*2,l,mid);    build(p*2+1,mid+1,r);    sum[p]=sum[p*2]+sum[p*2+1];}char get(){    char ch=getchar();    while (ch!='A'&&ch!='Q') ch=getchar();    return ch;}void mark(int p,int l,int r,ll c,ll d){    tree[p]+=(ll)c*(r-l+1)+d*sum[p];    a[p]+=c;    b[p]+=d;}void down(int p,int l,int r){    int mid=(l+r)/2;    if (a[p]||b[p]){        mark(p*2,l,mid,a[p],b[p]);        mark(p*2+1,mid+1,r,a[p],b[p]);        a[p]=b[p]=0;    }}void change(int p,int l,int r,int a,int b,ll c,ll d){    if (l==a&&r==b){        mark(p,l,r,c,d);        return;    }    down(p,l,r);    int mid=(l+r)/2;    if (b<=mid) change(p*2,l,mid,a,b,c,d);    else if (a>mid) change(p*2+1,mid+1,r,a,b,c,d);    else{        change(p*2,l,mid,a,mid,c,d);        change(p*2+1,mid+1,r,mid+1,b,c,d);    }    tree[p]=tree[p*2]+tree[p*2+1];}ll query(int p,int l,int r,int a,int b){    if (l==a&&r==b) return tree[p];    down(p,l,r);    int mid=(l+r)/2;    if (b<=mid) return query(p*2,l,mid,a,b);    else if (a>mid) return query(p*2+1,mid+1,r,a,b);    else return query(p*2,l,mid,a,mid)+query(p*2+1,mid+1,r,mid+1,b);}int main(){    freopen("truetears.in","r",stdin);freopen("truetears.out","w",stdout);    n=read();m=read();    fo(i,2,n){        j=read();        add(j,i);    }    d[1]=1;    dfs(1);    build(1,1,n);    while (m--){        ch=get();        if (ch=='A'){            j=read();k=read();            change(1,1,n,dfn[j],dfn[j]+size[j]-1,k-d[j],1);        }        else{            j=read();            printf("%lld\n",query(1,1,n,dfn[j],dfn[j]+size[j]-1));        }    }}
0 0