题目大意:
给出一棵以1为根的树,形式是从节点2开始给出每个节点的父亲节点;然后是m次操作,操作分为两种,1 v, x, k,表示在以v为根的字数上添加,添加的法则是看这个节点与v节点的距离为i的话,加上x-i*k;2 v查询节点v的值。
解题方法:
一颗树不好解决,dfs一下,将树形转化为线性。
按在题目要求对于1操作,我们将区域内所有的点都加上x+dep【v】*k
对于2操作,我们对于求出来的点数值减去dep【v】*k。
如何求见修改呢?
add(l,v),add(r+1,-v)就ok了
我的代码:
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#define maxn 1000000
#define MOD 1000000007
using namespace std;
int n,m,dep[maxn];
vector <int> po[maxn];
int l[maxn],r[maxn],totl;
int dfs(int v,int fa){
//cout<<v<<endl;
l[v]=totl++;
if (v==1) dep[v]=1;
else dep[v]=dep[fa]+1;
for (int i=0;i<po[v].size();i++)
dfs(po[v][i],v);
r[v]=totl-1;
return 0;
}
long long tree1[maxn],tree2[maxn];
int add1(int x,long long v){
for (int i=x;i<=n;i+=i&(-i))
tree1[i]=(tree1[i]+v)%MOD;
return 0;
}
int add2(int x,int v){
for (int i=x;i<=n;i+=i&(-i))
tree2[i]=(tree2[i]+v)%MOD;
return 0;
}
long long sum(int x){
long long a=0,b=0;
for (int i=l[x];i>0;i-=i&(-i)){
a+=tree1[i];
b+=tree2[i];
}
return ((a-b*dep[x])%MOD+MOD)%MOD;
}
int main (){
//freopen("test.in","r",stdin);
while (~scanf("%d",&n)){
memset(dep,0,sizeof(dep));
memset(tree1,0,sizeof(tree1));
memset(tree2,0,sizeof(tree2));
for (int i=1;i<=n;i++) po[i].clear();
for (int i=2;i<=n;i++){
int a;scanf("%d",&a);
po[a].push_back(i);
}
totl=1;dfs(1,0);
scanf("%d",&m);
for (int i=1;i<=m;i++){
int op,v;scanf("%d%d",&op,&v);
if (op==1){
long long x,k;
cin>>x>>k;
add1(l[v],(x+dep[v]*k));
add1(r[v]+1,-(x+dep[v]*k));
add2(l[v],k);
add2(r[v]+1,-k);
}
else {
cout<<sum(v)<<endl;
}
}
}
return 0;
}