【51nod1462】树据结构

来源:互联网 发布:3d打鱼源码 编辑:程序博客网 时间:2024/06/06 04:26

Description

给一颗以1为根的树。
每个点有两个权值:vi, ti,一开始全部是零。
Q次操作:
读入o, u, d
o = 1 对u到根上所有点的vi += d
o = 2 对u到根上所有点的ti += vi * d
最后,输出每个点的ti值(n, Q <= 100000)
有50%的数据N,Q <= 10000
注:所有数64位整数不会爆。

Solution

我们考虑用树剖来做这道题。
对于一个操作x,我们用树链剖分,但现在问题来了,怎样维护v和t呢?
我们对于线段树的每一位存下一个v,v1,t分别表示仅在该子树拥有的操作1,该子树及其父亲传下的操作1以及该子树同时拥有t。每一次操作有一个lzv,lzt表示懒标记下传。下传时v1 son+=lzv,lzv son+=lzv,t son+=t+lzt*v,lzt son+=t+lzt*v,最后把lzt,lzv,t清零。

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long longusing namespace std;const int maxn=6e5+5;struct code{    ll t,v,v1,lv,lt; }f[maxn];int first[maxn],last[maxn],next[maxn],b[maxn],dfn[maxn],size[maxn],son[maxn],fa[maxn],top[maxn];ll n,i,t,j,k,l,x,y,z,p,num,m,ans[maxn];void lian(int x,int y){    last[++num]=y;next[num]=first[x];first[x]=num;}void dg(int x){    int t;size[x]++;    for (t=first[x];t;t=next[t]){        fa[last[t]]=x;dg(last[t]),size[x]+=size[last[t]];        if (size[last[t]]>size[son[x]]) son[x]=last[t];    }}void dg1(int x){    int t;b[++num]=x;dfn[x]=num;    if (son[x]) top[son[x]]=top[x],dg1(son[x]);    for (t=first[x];t;t=next[t])        if (last[t]!=son[x]) top[last[t]]=last[t],dg1(last[t]);}void make(int v){    int x=v*2,y=v*2+1;    f[x].v1+=f[v].lv;f[x].lv+=f[v].lv,f[x].t+=f[v].t+f[x].v*f[v].lt;f[x].lt+=f[v].lt;    f[y].v1+=f[v].lv;f[y].lv+=f[v].lv,f[y].t+=f[v].t+f[y].v*f[v].lt;f[y].lt+=f[v].lt;    f[v].lv=f[v].lt=f[v].t=0;}void change(int l,int r,int v,int x,int y){    int mid=(l+r)/2;    if ((f[v].lv||f[v].lt)&&l<r) make(v);    if (l>=x && r<=y){        if (z==1)f[v].v+=p,f[v].v1+=p,f[v].lv+=p;        else f[v].t+=f[v].v1*p,f[v].lt+=p;        return;    }    if (l<=y && mid>=x) change(l,mid,v*2,x,y);    if (mid<y && r>=x) change(mid+1,r,v*2+1,x,y);}void find(int l,int r,int v){    int mid=(l+r)/2;    if ((f[v].lv||f[v].lt)&&l<r) make(v);    if (l==r){        ans[b[l]]=f[v].t;        return;    }    find(l,mid,v*2);find(mid+1,r,v*2+1);}int main(){//  freopen("data.in","r",stdin);freopen("data.out","w",stdout);    scanf("%lld",&n);    for (i=2;i<=n;i++)        scanf("%lld",&x),lian(x,i);    dg(1);top[1]=1;num=0;    dg1(1);scanf("%lld",&m);    for (i=1;i<=m;i++){        scanf("%lld%lld%lld",&z,&x,&p);        while (x)             change(1,n,1,dfn[top[x]],dfn[x]),x=fa[top[x]];    }    find(1,n,1);    for (i=1;i<=n;i++)        printf("%lld\n",ans[i]);}
1 0
原创粉丝点击