CodeForces - 396C On Changing Tree(树状数组)
Posted bztminamoto
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 396C On Changing Tree(树状数组)相关的知识,希望对你有一定的参考价值。
题目大意
给定一棵以1为根的树,初始时所有点为0
给出树的方式是从节点2开始给出每一个点的父亲
然后是 $m$ 次操作,分为两种
$1 v,k,x$ 表示在以v为根的子树中的每一个点上添加 $x-i*k$( $i$ 表示节点与 $v$ 的距离)(包括点 $v$ )
$2 v$ 查询节点 $v$ 的值
输出每一个2操作的答案模 $1e9+7$ 的值
题解
话说真没想到这题竟然这么简单……死活都想不出来……
先dfs预处理出每一个节点的dfs序,以及子树代表的区间$ls$和$rs$,以及每一个点的深度$dep$
假设先$add(ls[v],x+dep[v]*k),add(rs[v]+1,-x-dep[v]*k)$,然后用树状数组维护前缀和,树状数组设为$c1$
可以发现,$v$这个点多加去了$dep[v]*k$,要减掉。同理可得,$v$的所有子树都要减掉$dep[j]*k$($j$为$v$的子节点)
可以证明以上这么乱搞之后每一个点的值都加上了正确的数
乱证:$j$节点经过这一操作后加上了$dep[v]*k-dep[j]*k=k*(dep[j]-dep[v])=k*dis[v,j]$
然后证明每一个节点都加上了正确的数值
那么只要再开一个树状数组维护前缀$k$就可以了
查询的答案就是$sum(ls[v],c1)-sum(ls[v],c2)*dep[v]$
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #define ll long long 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 inline int read(){ 9 #define num ch-‘0‘ 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch==‘-‘)&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 char sr[1<<21],z[20];int C=-1,Z; 19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 20 inline void print(ll x){ 21 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 22 while(z[++Z]=x%10+48,x/=10); 23 while(sr[++C]=z[Z],--Z);sr[++C]=‘ ‘; 24 } 25 const int N=300005,mod=1e9+7; 26 int ver[N],head[N],Next[N],dep[N]; 27 int ls[N],rs[N]; 28 ll c[2][N]; 29 int n,tot,q,cnt; 30 inline void add(int x,ll val,int k){ 31 for(int i=x;i<=n;i+=i&(-i)) 32 (c[k][i]+=val)%=mod; 33 } 34 inline ll sum(int x){ 35 ll a=0,b=0; 36 for(int i=ls[x];i;i-=i&(-i)){ 37 a+=c[0][i],b+=c[1][i]; 38 } 39 return ((a-b*dep[x])%mod+mod)%mod; 40 } 41 void dfs(int u,int fa){ 42 ls[u]=++cnt; 43 dep[u]=dep[fa]+1; 44 for(int i=head[u];i;i=Next[i]) dfs(ver[i],u); 45 rs[u]=cnt; 46 } 47 int main(){ 48 //freopen("testdata.in","r",stdin); 49 n=read(); 50 for(int i=2;i<=n;++i){ 51 int fa=read(); 52 ver[++tot]=i,Next[tot]=head[fa],head[fa]=tot; 53 } 54 dfs(1,0); 55 q=read(); 56 while(q--){ 57 int opt=read(),v=read(); 58 if(opt&2) print(sum(v)); 59 else{ 60 ll x=read(),k=read(); 61 add(ls[v],x+dep[v]*k,0); 62 add(rs[v]+1,-x-dep[v]*k,0); 63 add(ls[v],k,1); 64 add(rs[v]+1,-k,1); 65 } 66 } 67 Ot(); 68 return 0; 69 }
以上是关于CodeForces - 396C On Changing Tree(树状数组)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces 869 C The Intriguing Obsession
Codeforces Round #439 (Div. 2) Problem C (Codeforces 869C) - 组合数学
C - The Intriguing Obsession /* Codeforces Round #439 */ (dp )