CodeForces 396C On Changing Tree

On Changing Tree

Time Limit: 2000ms

Memory Limit: 262144KB

This problem will be judged on CodeForces. Original ID: 396C
64-bit integer IO format: %I64d      Java class name: (Any)

You are given a rooted tree consisting of n vertices numbered from 1 to n. The root of the tree is a vertex number 1.

Initially all vertices contain number 0. Then come q queries, each query has one of the two types:

  • The format of the query: 1 v x k. In response to the query, you need to add to the number at vertex v number x; to the numbers at the descendants of vertex v at distance 1, addx - k; and so on, to the numbers written in the descendants of vertex v at distance i, you need to add x - (i·k). The distance between two vertices is the number of edges in the shortest path between these vertices.
  • The format of the query: 2 v. In reply to the query you should print the number written in vertex v modulo 1000000007 (109 + 7).

Process the queries given in the input.

Input

The first line contains integer n (1 ≤ n ≤ 3·105) — the number of vertices in the tree. The second line contains n - 1 integers p2, p3, ... pn (1 ≤ pi < i), where pi is the number of the vertex that is the parent of vertex i in the tree.

The third line contains integer q (1 ≤ q ≤ 3·105) — the number of queries. Next q lines contain the queries, one per line. The first number in the line is type. It represents the type of the query. If type = 1, then next follow space-separated integers v, x, k (1 ≤ v ≤ n; 0 ≤ x < 109 + 7; 0 ≤ k < 109 + 7). If type = 2, then next follows integer v (1 ≤ v ≤ n) — the vertex where you need to find the value of the number.

Output

For each query of the second type print on a single line the number written in the vertex from the query. Print the number modulo 1000000007 (109 + 7).

Sample Input

Input

31 131 1 2 12 12 2

Output

21

Hint

You can read about a rooted tree here: http://en.wikipedia.org/wiki/Tree_(graph_theory).

Source

Codeforces Round #232 (Div. 1)

解题:树状数组或者线段树

给出一棵以1为根的树,形式是从节点2开始给出每个节点的父亲节点;

然后是m次操作,操作分为两种,1 v, x, k,表示在以v为根的字数上添加,添加的法则是看这个节点与v节点的距离为i的话,加上x-i*k;

2 v查询节点v的值。

发现相加的性质,维护两个树状数组

给c1 结点代表的区间都加上x + d[u]*k 给第二个树状数组也加上 d[u]*k

假设u是v的父节点 当计算v的时候 可以用$ x + d[u]*k - d[v]*k $

正是我们要的$x + k\times (d[u] - d[v])$

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 const int maxn = 300010;
 5 const int mod = 1000000007;
 6 vector<int>g[maxn];
 7 LL c[2][maxn],val[2];
 8 int n,m,L[maxn],R[maxn],d[maxn],clk;
 9 void update(int i){
10     while(i < maxn){
11         c[0][i] += val[0];
12         c[1][i] += val[1];
13         c[0][i] %= mod;
14         c[1][i] %= mod;
15         i += i&-i;
16     }
17 }
18 LL query(int i){
19     LL sum[2] = {0},dep = d[i];
20     i = L[i];
21     while(i > 0){
22         sum[0] += c[0][i];
23         sum[1] += c[1][i];
24         sum[0] %= mod;
25         sum[1] %= mod;
26         i -= i&-i;
27     }
28     return ((sum[0] - dep*sum[1])%mod + mod)%mod;
29 }
30 void dfs(int u,int dep){
31     L[u] = ++clk;
32     d[u] = dep;
33     for(int i = g[u].size()-1; i >= 0; --i)
34         dfs(g[u][i],dep+1);
35     R[u] = clk;
36 }
37 int main(){
38     int u,op,x,y,z;
39     while(~scanf("%d",&n)){
40         for(int i = clk = 0; i <= n; ++i) g[i].clear();
41         for(int i = 2; i <= n; ++i){
42             scanf("%d",&u);
43             g[u].push_back(i);
44         }
45         dfs(1,0);
46         memset(c,0,sizeof c);
47         scanf("%d",&m);
48         while(m--){
49             scanf("%d%d",&op,&x);
50             if(op == 1){
51                 scanf("%d%d",&y,&z);
52                 val[0] = ((LL)y + (LL)d[x]*z)%mod;
53                 val[1] = z;
54                 update(L[x]);
55                 val[0] = -val[0];
56                 val[1] = -val[1];
57                 update(R[x]+1);
58             }else printf("%I64d\n",query(x));
59         }
60     }
61     return 0;
62 }

时间: 2024-11-18 14:58:14

CodeForces 396C On Changing Tree的相关文章

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

Codeforces 461B Appleman and Tree(树形dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每个节点的父亲节点,以及每个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量,保证每个联通分量有且仅有1个黑色节点.问有多少种分割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的分割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include <c

Educational Codeforces Round 25 G. Tree Queries

题目链接:Educational Codeforces Round 25 G. Tree Queries 题意: 给你一棵树,一开始所有的点全是黑色,有两种操作. 1 x 将x这个点变为黑色,保证第一个操作是这个. 2 x 询问x到任意黑色的点的简单路径上的最小节点编号. 题解: 首先将一个变为黑色的点当成树根,然后dfs一下,预处理出所有点的答案. 然后开一个变量记录一下当前变黑的点的答案cur=min(cur,dp[x]). 每次询问的时候答案就是min(cur,dp[x]). 如果觉得很神

Codeforces.280C.Game on Tree(期望)

题目链接 参考:浅谈期望的线性性(可加性) Codeforces 280C Game on Tree 概率dp 树上随机删子树 求删完次数的期望(这个的前半部分分析并没有看..) \(Description\) 给你一棵有\(n\)个白点的有根树,每次随机选择一个点,将它和它的子树中所有点染黑. 问期望操作多少次后所有点都被染黑? \(Solution\) 期望好玄啊..(好吧是我太弱) 因为概率具有可加性,一棵树可以分解为多棵子树,而子树分解的最终状态就是点,所以我们可以计算每个点的期望操作次

CF396C On Changing Tree

CF396C On Changing Tree 给定一棵以 \(1\) 为根的树,初始时所有点权为 \(0\) 有 \(m\) 次操作,分为两种 \(1\ u\ x\ k\) 表示给以 \(u\) 的子树中的每一个点 \(v\) 点权增加 \(x-k\times dis(u,\ v)\) \(2\ u\) 查询点 \(u\) 的点权模 \(10^9+7\) 的值 \(n,\ m\leq3\times10^5\) dfs序,树状数组 把操作 \(1\) 中的 \(dis(u,\ v)\) 拆成 \

Codeforces 348B:Apple Tree(DFS+LCM+思维)

http://codeforces.com/contest/348/problem/B 题意:给一棵树,每个叶子结点有w[i]个苹果,每个子树的苹果数量为该子树所有叶子结点苹果数量之和,要使得每个结点的各个子树苹果数量相等,求至少需要拿走的苹果数量. 思路:一开始以为只要使得所有子树之和相同就行了. 1 void dfs(int u, int fa) { 2 int num = 0, mi = INF; 3 for(int i = head[u]; ~i; i = edge[i].nxt) {

【CodeForces】343D Water tree (线段树好题!还未弄懂)

/* 此题的方法除了用线段树求子树,通过标记父亲,更新儿子的方法,来更新祖先,学习了. 对于建树的方法由于并没有说明父亲与儿子的顺序,所以需要通过两次添加. 并且pre变量可以获得父亲的位置,还未弄懂! */ #define _CRT_SECURE_NO_WARNINGS #include<cstring> #include<cstdio> #include<iostream> #include<algorithm> using namespace std;

Codeforces 620E New Year Tree(线段树)

题目链接 New Year Tree 考虑到ck <= 60,那么用位运算统计颜色种数 对于每个点,重新标号并算出他对应的进和出的时间,然后区间更新+查询. 用线段树来维护. 1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define rep(i, a, b) for (int i(a); i <= (b); ++i) 6 7 struct node{ 8 long long num, lazy; 9 } tree