CodeForces 396C

题目大意:

   给出一棵以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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值