编程之美初赛第一场 树

题目2 : 树

时间限制: 4000ms
单点时限: 2000ms
内存限制: 256MB

描述

有一个N个节点的树,其中点1是根。初始点权值都是0。

一个节点的深度定义为其父节点的深度+1,。特别的,根节点的深度定义为1。

现在需要支持一系列以下操作:给节点u的子树中,深度在l和r之间的节点的权值(这里的深度依然从整个树的根节点开始计算),都加上一个数delta。

问完成所有操作后,各节点的权值是多少。


为了减少巨大输出带来的开销,假设完成所有操作后,各节点的权值是answer[1..N],请你按照如下方式计算出一个Hash值(请选择合适的数据类型,注意避免溢出的情况)。最终只需要输出这个Hash值即可。


MOD =1000000007; // 10^9 + 7

MAGIC= 12347;

Hash =0;

For i= 1 to N do

   Hash = (Hash * MAGIC + answer[i]) mod MOD;

EndFor


输入

第一行一个整数T (1 ≤ T ≤ 5),表示数据组数。

接下来是T组输入数据,测试数据之间没有空行。

每组数据格式如下:

第一行一个整数N (1 ≤ N ≤ 105),表示树的节点总数。

接下来N - 1行,每行1个数,a (1 ≤ a ≤ N),依次表示2..N节点的父亲节点的编号。

接下来一个整数Q(1 ≤ Q ≤ 105),表示操作总数。

接下来Q行,每行4个整数,u, l, r, delta (1 ≤ u ≤ N, 1 ≤ l ≤ r ≤ N, -109 ≤ delta ≤ 109),代表一次操作。


输出

对每组数据,先输出一行“Case x: ”,x表示是第几组数据,然后接这组数据答案的Hash值。


数据范围


小数据:1 ≤ N, Q ≤ 1000

大数据:1 ≤ N, Q ≤ 105


样例解释

点1的子树中有1,2,3三个节点。其中深度在2-3之间的是点2和点3。

点2的子树中有2,3两个节点。其中没有深度为1的节点。

所以,执行完所有操作之后,只有2,3两点的权值增加了1。即答案是0 1 1。再计算对应的Hash值即可。




样例输入
1
3
1
2
2
1 2 3 1
2 1 1 1
样例输出
Case 1: 12348
 
    
Idea: SegMent Tree
 
    
/*
 * File Name:B.cpp
 * Create Time:14:08:35,星期六, 19 四月 2014.
 * Author: qqspeed
 */

#include<algorithm>
#include<bitset>
#include<deque>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<limits>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<sstream>
#include<stack>
#include<vector>
#include<complex>
using namespace std;

#define FOR(i,b,e) for(__typeof(b)i=(b);i!=(e);i++)
#define FOR_EACH(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();i++)
#define rep(i,s,t) for(int i=s;i<t;i++)
#define INF ~0U>>2
#define L t<<1
#define	R t<<1|1
#define PI acos(-1.0)
typedef complex<double>Com;
typedef pair<int,int> ii;
typedef long long ll;
typedef unsigned long long ull;

inline void DATA(char *s,char *d){
    freopen(s,"r",stdin);
    freopen(d,"w",stdout);
}

inline int input(){
    int ret=0;bool isN=0;char c=getchar();
    while(c<'0' || c>'9'){
        if(c=='-') isN=1;
        c=getchar();
    }
    while(c>='0' && c<='9'){
        ret=ret*10+c-'0';c=getchar();
    }
    return isN?-ret:ret;
}

inline void output(int x){
    if(x<0){
        putchar('-');x=-x;
    }
    int len=0,data[10];
    while(x){
        data[len++]=x%10;x/=10;
    }
    if(!len)	data[len++]=0;
    while(len--)
        putchar(data[len]+48);
    putchar('\n');
}

#define clr(a) memset(a,0,sizeof(a))
#define N 100005
#define mod 1000000007
#define magic 12347
int tt,n;
vector<int>v[N];
int dis[N];
int q;
int u,l,r,delta;
int to[N],rTo[N],last[N];
int cnt;

inline void dfs(int now,int pre){
    dis[now]=dis[pre]+1;
    to[now]=cnt;
    rTo[cnt]=now;
    cnt++;
    int s=v[now].size();
    rep(i,0,s){
        dfs(v[now][i],now);
    }
    last[now]=cnt-1;
}

struct node{
    int l,r;
    int Min,Max;
    ll val;
}root[N<<2];

inline void push_up(int t){
    root[t].Min=min(root[L].Min,root[R].Min);
    root[t].Max=max(root[L].Max,root[R].Max);
}
inline void push_down(int t){
    if(root[t].val!=0){
        root[L].val+=root[t].val;
        root[R].val+=root[t].val;
        root[t].val=0;
    }
}
inline void build(int t,int x,int y){
    root[t].l=x,root[t].r=y;
    root[t].val=0;
    if(x==y){
        root[t].Min=root[t].Max=dis[rTo[x]];
        return;
    }
    int mid=(x+y)>>1;
    build(L,x,mid);build(R,mid+1,y);
    push_up(t);
}
inline void add(int t,int x,int y,int a,int b,int del){
    int l=root[t].l,r=root[t].r;
    if(root[t].Min>b || root[t].Max<a) return;
    if(l>=x && r<=y && root[t].Min>=a && root[t].Max<=b){
        root[t].val+=del;
        return;
    }
    if(l==r) return;
    push_down(t);
    int mid=(l+r)>>1;
    if(y<=mid) add(L,x,y,a,b,del);
    else if(x>mid) add(R,x,y,a,b,del);
    else{
        add(L,x,mid,a,b,del);
        add(R,mid+1,y,a,b,del);
    }
}
inline ll query(int t,int x){
    int l=root[t].l,r=root[t].r;
    if(l==r) return root[t].val;
    push_down(t);
    int mid=(l+r)>>1;
    if(x<=mid) return query(L,x);
    return query(R,x);
}
inline ll Hash(){
    ll ans=0;
    rep(i,1,n+1){
        ans=(ans*magic+query(1,to[i]))%mod;
    }
    return ans;
}
int main() {
    //ios::sync_with_stdio(false);
    //DATA();
    tt=input();
    rep(ca,1,tt+1){
        n=input();
        cnt=1;
        clr(dis),clr(to),clr(rTo),clr(last);
        rep(i,0,n+1) v[i].clear();
        rep(i,2,n+1){
            l=input();
            v[l].push_back(i);
        }
        dis[0]=0;
        dfs(1,0);
        build(1,1,cnt-1);
        q=input();
        rep(i,1,q+1){
            u=input(),l=input(),r=input(),delta=input();
            int s=to[u],e=last[u];
            add(1,s,e,l,r,delta);
        }
        //rep(i,1,n+1)printf("%d \n",val[i]);
        printf("Case %d: %lld\n",ca,Hash());
    }
    return 0;
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值