Codeforces Round 232 Div 1 C On Changing Tree 树状数组 或 线段树

来源:互联网 发布:旋转后的成分矩阵 编辑:程序博客网 时间:2024/05/16 17:24

题目地址

http://codeforces.com/problemset/problem/396/C

树状数组,对于搞括号序列还是有一手的,关键是因为括号序列的题老是逮着某个点询问,而他的更新又往往是涉及一棵子树。

当然,树状数组的更新也要满足可加性的。

对于向某棵子树上的节点均增加 X 这种操作,我们可以在括号序列的左端点增加x,右端点+1处增加 -x,这样使用 sum 查询到内部的时候就会增加x,并且不会影响外部的节点。

但是这个题,每个节点增加的并不是相同的数值,而是一个和被改变节点相对位置有关的值。

对于这种相对位置,我们可以改成绝对位置。

比如 求某段区间的和,我们可以预先求出每个节点到0 的和,然后求左右端点的差。

这里,我们可以求出每个点的绝对深度,用 deep-deep_change 来表示相对深度、

于是

增加 x 这个操作的影响变为

x - (deep - deepChange )*k = (x + deepChange*k) - deep * k

好,对于这个式子,前面一项满足可加性,后面一项满足可加性,结束了。。。两棵BIT

 

#include <iostream>#include <stdio.h>#include <algorithm>#include <string.h>#include <queue>#include <map>#include <set>#include <cmath>using namespace std;#define MAX 700000 #define INF 0x3f3f3f3f#define MS(x) memset(x,0,sizeof(x))#define ll long long#define P pair<int,int>#define fst first#define sec second#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1#define MOD 1000000007int cnt=0;void getMod(ll &num){num=num%MOD;}struct bit{ll data[MAX];ll sum(int i){ll res=0;while(i){res+=data[i];i-=i&(-i);getMod(res);}return res;}void add(int i,ll x){while(i<=cnt){data[i]+=x;getMod(data[i]);i+=i&(-i);}}}Sub,Sum;int L[MAX],R[MAX],D[MAX];vector<int> G[MAX];void dfs(int x,int fa,int deep){D[x]=deep;L[x]=++cnt;for(int i=0;i<G[x].size();i++){int v=G[x][i];if(v!=fa)dfs(v,x,deep+1);}R[x]=++cnt;}void init(){for(int i=0;i<MAX;i++)G[i].clear();cnt=0;MS(Sum.data);MS(Sub.data);}int main(){int n;while(scanf("%d",&n)!=EOF){init();for(int i=2;i<=n;i++){int f;scanf("%d",&f);G[f].push_back(i);}dfs(1,0,0);int q;scanf("%d",&q);while(q--){int t;scanf("%d",&t);if(t==1){ll v,x,k;scanf("%I64d%I64d%I64d",&v,&x,&k);Sum.add(L[v],x+D[v]*k);Sum.add(R[v]+1,-x-D[v]*k);Sub.add(L[v],k);Sub.add(R[v]+1,-k);}if(t==2){int v;scanf("%d",&v);ll a=Sum.sum(L[v]);ll b=Sub.sum(L[v])*D[v];ll ans=((a-b)%MOD+MOD)%MOD;cout<<ans<<endl;}}}return 0;}

0 0