JZOJ 4895 三部曲(线段树)

来源:互联网 发布:欧洲女装品牌 知乎 编辑:程序博客网 时间:2024/05/20 23:59

题目

因为外来的入侵,国王决定在某些城市加派士兵。所有城市初始士兵数量为0。当城市 被加派了k名士兵时。城市i的所有子城市需要被加派k+1名士兵。这些子城市的所有子城市需要被加派k+2名士兵。以此类推。
当然,加派士兵的同时,国王也需要不断了解当前的情况。于是他随时可能询问以城市i为根的子树中的所有城市共被加派了多少士兵。
你现在是国王的军事大臣,你能回答出国王的每个询问么?

n<=50000,q<=100000
时间限制 1s
空间限制 512M

解题思路

把树转化成一条线,每棵子树就会对应线段上一个连续的区间,再用线段树维护区间信息。这时候问题来了,区间内每个点加的值不同,怎么办呢?我们可以把k拆分成k’+dep[x],这样lazy tag就可以分别叠加了,然后把用两个线段树区间标记分别维护k’和dep[x]累加的值就可以了。

#include<cstdio>#include<cstring>#include<algorithm>#define maxn 300006#define fr(i,a,b) for(i=a;i<=b;i++)using namespace std;typedef long long ll;struct poi{    int x;    poi *nex;} *a[maxn];void link(int x,int y){    poi *p=new poi;    p->x=y;    p->nex=a[x];    a[x]=p;    return;}int i,n,q,x,y,tot,d[maxn],fa[maxn],dep[maxn],siz[maxn],pos[maxn];ll s,sum[maxn],tr[maxn*4],c1[maxn*4],c2[maxn*4];char st[4];void dfs(int x){    poi *p=new poi;    siz[x]=1,d[++tot]=x,pos[x]=tot;    dep[x]=dep[fa[x]]+1;    for(p=a[x];p;p=p->nex)    {        fa[p->x]=x;        dfs(p->x);        siz[x]+=siz[p->x];    }    return;}void update(int v,int st,int en){    int m=(st+en) >> 1;    if (!c1[v] && !c2[v]) return;    tr[v+v]=(tr[v+v]+c1[v]*(sum[m]-sum[st-1])+c2[v]*(m-st+1));    tr[v+v+1]=(tr[v+v+1]+c1[v]*(sum[en]-sum[m])+c2[v]*(en-m));    c1[v+v]+=c1[v],c2[v+v]+=c2[v];    c1[v+v+1]+=c1[v],c2[v+v+1]+=c2[v];    c1[v]=c2[v]=0;    return;}void modify(int v,int st,int en,int l,int r,int x,int y){    if (st==l && en==r)    {        tr[v]+=(sum[en]-sum[st-1])+(en-st+1)*x;        ++c1[v],c2[v]+=x;        return;    }    update(v,st,en);    int m=(st+en) >> 1;    if (r<=m) modify(v+v,st,m,l,r,x,y);    else if (l>m) modify(v+v+1,m+1,en,l,r,x,y);    else    {        modify(v+v,st,m,l,m,x,y);        modify(v+v+1,m+1,en,m+1,r,x,y);    }    tr[v]=tr[v+v]+tr[v+v+1];    return;}void findd(int v,int st,int en,int l,int r){    if (st==l && en==r)    {        s=(s+tr[v]);        return;    }    update(v,st,en);    int m=(st+en) >> 1;    if (r<=m) findd(v+v,st,m,l,r);    else if (l>m) findd(v+v+1,m+1,en,l,r);    else    {        findd(v+v,st,m,l,m);        findd(v+v+1,m+1,en,m+1,r);    }    return;}int main(){    freopen("truetears.in","r",stdin);    freopen("truetears.out","w",stdout);    scanf("%d%d",&n,&q);    fr(i,2,n) scanf("%d",&x),link(x,i);    dfs(1);    fr(i,1,n) sum[i]=(sum[i-1]+dep[d[i]]);    fr(i,1,q)    {        scanf("%s%d",st+1,&x);        if (st[1]=='A')        {            scanf("%d",&y);            int kk=y-dep[x];            modify(1,1,n,pos[x],pos[x]+siz[x]-1,kk,1);            // modify2(1,1,n)        } else        {            s=0;            findd(1,1,n,pos[x],pos[x]+siz[x]-1);            printf("%lld\n",s);        }    }    return 0;}
0 0