fzu 2277 Change 线段树

Problem 2277 Change

Time Limit: 2000 mSec    Memory Limit : 262144 KB

 Problem Description

There is a rooted tree with n nodes, number from 1-n. Root’s number is 1.Each node has a value ai.

Initially all the node’s value is 0.

We have q operations. There are two kinds of operations.

1 v x k : a[v]+=x , a[v’]+=x-k (v’ is child of v) , a[v’’]+=x-2*k (v’’ is child of v’) and so on.

2 v : Output a[v] mod 1000000007(10^9 + 7).

 Input

First line contains an integer T (1 ≤ T ≤ 3), represents there are T test cases.

In each test case:

The first line contains a number n.

The second line contains n-1 number, p2,p3,…,pn . pi is the father of i.

The third line contains a number q.

Next q lines, each line contains an operation. (“1 v x k” or “2 v”)

1 ≤ n ≤ 3*10^5

1 ≤ pi < i

1 ≤ q ≤ 3*10^5

1 ≤ v ≤ n; 0 ≤ x < 10^9 + 7; 0 ≤ k < 10^9 + 7

 Output

For each operation 2, outputs the answer.

 Sample Input

131 131 1 2 12 12 2

 Sample Output

21

 Source

第八届福建省大学生程序设计竞赛-重现赛(感谢承办方厦门理工学院)

对于u的子树所在节点v(含u)
对v的影响为+  :    
x - (deep[v]-deep[u])*k
= x + deep[u]*k - deep[v]*k
分成两部分: 
Add:   x + deep[u]*k  , 区间更新
Sub: deep[v]*k , 区间更新,  deep[v]最后再乘
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;


public class Main {
	
	public static void main(String[] args) {
		new Task().solve();
	}
}



class Task {
	InputReader in = new InputReader(System.in) ;
	PrintWriter out = new PrintWriter(System.out) ;
	final long Mod = 1000000007L ;
	List<Integer>[] adj ; 
	int[] left , right  , deep ;
	int time ;
	
	void dfs(int u , int dep){
		left[u] = ++time ;
		deep[u] = dep ;
		for(int v : adj[u]){
			dfs(v , dep+1) ;
		}
		right[u] = time ;
	}
	
	long[] add , addSum , sub , subSum ;
	
	void down(int t){
		if(add[t] != 0){
			add[t<<1] += add[t] ;
			add[t<<1] %= Mod ;
			add[t<<1|1] += add[t] ;
			add[t<<1|1] %= Mod ;
			addSum[t<<1] += add[t] ;
			addSum[t<<1] %= Mod ;
			addSum[t<<1|1] += add[t] ;
			addSum[t<<1|1] %= Mod ;
			add[t] = 0 ;
		}
		if(sub[t] != 0){
			sub[t<<1] += sub[t] ;
			sub[t<<1] %= Mod ;
			sub[t<<1|1] += sub[t] ;
			sub[t<<1|1] %= Mod ;
			subSum[t<<1] += sub[t] ;
			subSum[t<<1] %= Mod ;
			subSum[t<<1|1] += sub[t] ;
			subSum[t<<1|1] %= Mod ;
			sub[t] = 0 ;
		}
	}
	
	void update(int L , int R , long toAdd , long toSub , int l , int r , int t){
		if(L <= l && r <= R){
			add[t] += toAdd ;
			add[t] %= Mod ;
			addSum[t] += toAdd ;
			addSum[t] %= Mod ;
			sub[t] += toSub ;
			sub[t] %= Mod ;
			subSum[t] += toSub ;
			subSum[t] %= Mod ;
			return ;
		}
		down(t) ;
		int m = (l + r) >> 1 ;
		if(L <= m){
			update(L, R, toAdd, toSub, l, m, t<<1) ;
		}
		if(R > m){
			update(L, R, toAdd, toSub, m+1, r, t<<1|1) ;
		}
	}
	
	long query(int i , int l , int r , int t , int dep){
		if(l == r){
			long reslut = addSum[t] - subSum[t] * dep % Mod ;
			reslut %= Mod ;
			reslut = (reslut + Mod) % Mod ;
			return reslut ;
		}
		down(t) ;
		int m = (l + r) >> 1 ;
	    if(i <= m){
	    	return query(i, l, m, t<<1 , dep) ;
	    }
	    else{
	    	return query(i, m+1, r, t<<1|1, dep) ;
	    }
	}
	
	void solve(){
		int t = in.nextInt() ;
		while(t-- > 0){
			int n = in.nextInt() ;
			adj = new List[n+1] ;
			for(int i = 1 ; i <= n ; i++){
				adj[i] = new ArrayList<Integer>() ;
			}
			for(int i = 2 ; i <= n ; i++){
				adj[in.nextInt()].add(i) ;
			}
			left = new int[n+1] ;
			right = new int[n+1] ;
			deep = new int[n+1] ;
			add = new long[n<<2] ;
			addSum = new long[n<<2] ;
			sub = new long[n<<2] ;
			subSum = new long[n<<2] ;
			Arrays.fill(add, 0); 
			Arrays.fill(addSum, 0); 
			Arrays.fill(sub , 0); 
			Arrays.fill(subSum , 0); 
			
			time = 0 ; 
			dfs(1 , 0) ;
			int q = in.nextInt() ;
			while(q-- > 0){
				if(in.nextInt() == 1){
					int u = in.nextInt() ;
					long x = in.nextLong() ;
					long k = in.nextLong() ;
					update(left[u] , right[u] , (x + deep[u] * k % Mod) % Mod, k, 1, n, 1) ;
				}
				else{
					int v = in.nextInt() ;
					out.println(query(left[v] , 1 , n , 1 , deep[v])) ;
				}
			}
		}  
		out.flush() ;
	}
}

class InputReader {    
    public BufferedReader reader;    
    public StringTokenizer tokenizer;    
    
    public InputReader(InputStream stream) {    
        reader = new BufferedReader(new InputStreamReader(stream), 32768);    
        tokenizer = new StringTokenizer("");    
    }    
    
    private void eat(String s) {    
        tokenizer = new StringTokenizer(s);    
    }    
    
    public String nextLine() {     
        try {    
            return reader.readLine();    
        } catch (Exception e) {    
            return null;    
        }    
    }    
    
    public boolean hasNext() {    
        while (!tokenizer.hasMoreTokens()) {    
            String s = nextLine();    
            if (s == null)    
                return false;    
            eat(s);    
        }    
        return true;    
    }    
    
    public String next() {    
        hasNext();    
        return tokenizer.nextToken();    
    }    
    
    public int nextInt() {    
        return Integer.parseInt(next());    
    }    
    
    public int[] nextInts(int n) {    
        int[] nums = new int[n];    
        for (int i = 0; i < n; i++) {    
            nums[i] = nextInt();    
        }    
        return nums;    
    }    
    
    public long nextLong() {    
        return Long.parseLong(next());    
    }    
    
    public double nextDouble() {    
        return Double.parseDouble(next());    
    }    
    
    public BigInteger nextBigInteger() {    
        return new BigInteger(next());    
    }    
    
}    




             


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值