fzu 2277 Change [第八届福建省大学生程序设计竞赛 Problem F] [线段树]
来源:互联网 发布:上海数据录入公司 编辑:程序博客网 时间:2024/06/05 20:01
点击打开题目
题意: 给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作
(1) 1 v k x : a[v] += x, a[v '] += x – k(v '为v的儿子), a[v ' '] += x – 2 * k(v ' '是v '的儿子) ... ;
(2) 2 v : 输出a[v] % (1e9 + 7);
分析: 先dfs遍历, 得到这棵树的dfs序列, 并且记录每个结点的子孙(包括自己)的起始和结束位置, 以及每个结点的深度. 则对于1操作: v的每个子孙结点的变化情况为a[i] += x – (deep[i] – deep[v])* k; 其中x + k * deep[v]对所有结点贡献相同,而deep[i] * k对每个结点的贡献度取决于结点i的深度. 所以可以用线段树, 对于每次操作一,所有v的子孙结点都加上x + k * deep[v], 然后对于deep[i] * k每次记录k, 到最后更新的时候再乘以结点的深度即可.
#include<cstdio>#include<cstring>#include<algorithm>#include<vector>typedef long long ll;const int maxn = 3 * 1e5 + 10;const ll mod = 1e9 + 7;using namespace std;vector<int> G[maxn];int node[maxn], id1[maxn], id2[maxn], dep[maxn];ll xx[maxn << 2], kk[maxn << 2];int k, n;int Scan(){ int res = 0, ch, flag = 0; if((ch = getchar()) == '-') flag = 1; else if(ch >= '0' && ch <= '9') res = ch - '0'; while((ch = getchar()) >= '0' && ch <= '9' ) res = res * 10 + ch - '0'; return flag ? -res : res;}ll Scan_l(){ ll res = 0; int ch, flag = 0; if((ch = getchar()) == '-') flag = 1; else if(ch >= '0' && ch <= '9') res = ch - '0'; while((ch = getchar()) >= '0' && ch <= '9' ) res = res * 10 + ch - '0'; return flag ? -res : res;}void dfs(int u, int fa, int d) { node[k] = u; id1[u] = id2[u] = k; dep[k++] = d; for(int i = 0; i < G[u].size(); i++) { ll v = G[u][i]; if(v == fa) continue; dfs(v, u, d + 1); } id2[u] = k - 1;}void pushdown(int rt) { xx[rt << 1] += xx[rt]; xx[rt << 1] %= mod; xx[rt << 1 | 1] += xx[rt]; xx[rt << 1 | 1] %= mod; kk[rt << 1] += kk[rt]; kk[rt << 1] %= mod; kk[rt << 1 | 1] += kk[rt]; kk[rt << 1 | 1] %= mod; xx[rt] = 0; kk[rt] = 0;}void update(int L, int R, int l, int r, int rt, ll c, ll d) { if(L <= l && r <= R) { xx[rt] = ((xx[rt] + c) % mod + mod) % mod; kk[rt] = ((kk[rt] + d) % mod + mod) % mod; return ; } pushdown(rt); int m = (l + r) / 2; if(L <= m) update(L, R, l, m, rt << 1, c, d); if(m < R) update(L, R, m + 1, r, rt << 1 | 1, c, d);}ll query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) { return xx[rt] + dep[L] * kk[rt]; } pushdown(rt); int m = (l + r) / 2; if(R <= m) return query(L, R, l, m, rt << 1); else return query(L, R, m + 1, r, rt << 1 | 1);}int main() { int t, g, q; t = Scan(); while(t--) { k = 1; memset(xx, 0, sizeof xx); memset(kk, 0, sizeof kk); for(int i = 0; i < maxn; i++) G[i].clear(); n = Scan(); for(int i = 2; i <= n; i++) { g = Scan(); G[g].push_back(i); } dfs(1, 0, 1); q = Scan(); while(q--) { int op, root; ll x, y; op = Scan(); if(op == 1) { root = Scan(); x = Scan_l(); y = Scan_l(); update(id1[root], id2[root], 1, n, 1, x + dep[id1[root]] * y, -y); } if(op == 2) { root = Scan(); printf("%I64d\n", (query(id1[root], id1[root], 1, n, 1) % mod + mod) % mod); } } } return 0;}
阅读全文
0 0
- fzu 2277 Change [第八届福建省大学生程序设计竞赛 Problem F] [线段树]
- 第八届福建省大学生程序设计竞赛-重现赛(F Problem 2277 Change)DFS序+树状数组
- 第八届福建省大学生程序设计竞赛 FZU 2277 Change (dfs序+树状数组)
- fzu 2278 YYS [第八届福建省大学生程序设计竞赛 Problem G] [概率]
- fzu 2275 Game [第八届福建省大学生程序设计竞赛 Problem D] [字符串匹配]
- fzu 2281 Trades [第八届福建省大学生程序设计竞赛 Problem J Trades] [贪心]
- 第八届福建省大学生程序设计竞赛
- 第八届福建省大学生程序设计竞赛 FZU 2273 Triangles (计算几何)
- FZU Problem 2102 Solve equation 第三届福建省大学生程序设计竞赛
- FZU Problem 2221 RunningMan(思维考查)——第六届福建省大学生程序设计竞赛-重现赛
- FZU Problem 2214 Knapsack problem(01背包,超大背包)——第六届福建省大学生程序设计竞赛-重现赛
- 2017第八届福建省大学生程序设计竞赛总结
- 第八届福建省大学生程序设计竞赛训练总结【7/12】
- 第八届福建省大学生程序设计竞赛 D.Game【思维+KMP】
- 第八届福建省大学生程序设计竞赛-重现赛 A Frog
- 第八届福建省大学生程序设计竞赛-重现赛I Magic
- 7.22.17 第八届福建省大学生程序设计竞赛-重现赛
- 第八届福建省大学生程序设计竞赛 G.YYS【期望+大数】
- Java 正则表达式入门
- 1041. 考试座位号
- WebService的重要术语
- 银行家算法解决死锁问题
- FileInputStream对象读文件示例
- fzu 2277 Change [第八届福建省大学生程序设计竞赛 Problem F] [线段树]
- Swift 单例
- LeetCode 520 Detect Capital
- 646. Maximum Length of Pair Chain
- 【华为机试】质数因子
- Makefile文件编写
- 服务化框架-分布式Unique ID的生成方法一览
- JDBC之实现一个最基本的数据库连接池
- RBAC权限管理