编程之美初赛第一场 树
来源:互联网 发布:js 过滤换行符 编辑:程序博客网 时间:2024/04/30 11:07
- 样例输入
131221 2 3 12 1 1 1
- 样例输出
Case 1: 12348
描述
有一个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值即可。
注意表示为father的时候每个结点的高度并不是可以直接得到的,需要深搜,先贴一下我的错误代码:
#include <stdio.h>#include <vector>#include <string.h>#include <iostream>#include <memory.h>using namespace std;int T, i, j, t, N, Q, u, l, r, delta, d[100002], answer[100002],father; vector<int> tree[100002];void dfs(int u, int l, int r, int delta) { if (d[u] >= l && d[u] <= r) answer[u] += delta; for (int i = 0; i < tree[u].size(); ++i) { dfs(tree[u][i], l, r, delta); }}int main() { freopen("E:\\练习\\testForVS2012\\test\\test\\in.txt","r",stdin); const long long MOD =1000000007, MAGIC= 12347; long long hash = 0; scanf("%d",&T); for (t = 1; t <= T; ++t) { scanf("%d", &N); memset(d, 0, sizeof(d)); memset(answer, 0, sizeof(answer)); hash = 0; d[1] = 1; for (i = 2; i <= N; ++i) { scanf("%d",&father); d[i] = d[father] + 1; tree[father].push_back(i); } scanf("%d", &Q); for (i = 0; i < Q; ++i) { scanf("%d%d%d%d",&u, &l, &r, &delta); dfs(u, l, r, delta); } for (i = 1; i <= N; ++i) hash = (hash * MAGIC + answer[i]) % MOD; printf("Case %d: %lld\n",t,hash); for (i = 1; i <= N; ++i) tree[i].clear(); } return 0;}
据说如果把上面的d[i] = d[father] + 1改掉我上面暴力的方法都可以通过,但是比较好的方法是用树状数组把查询都先记录下来,然后再深搜一次更新,补充一下树状数组的概念:
树状数组的结构图
intlowbit(intx){
returnx&(x^(x–1));
}
intlowbit(intx){
returnx&(-x);
}
#include <cstdio>#include <cstring>#include <iostream>using namespace std;const int MAXN = 100000 + 100;const int MOD = 1000000007;int qlast[MAXN], last[MAXN];struct QQ{ int l, r, delta; int pre;} q[MAXN];struct EE { int y; int pre;} e[MAXN];long long ans[MAXN];long long hash1;long long t[MAXN];int n;void add(int d, int del){ if (d < 1) return; d = n - d + 1; while (d <= n) { t[d] += del; d += (d & (-d)); }}long long getsum(int d){ d = n - d + 1; long long ret = 0; while (d) { ret += t[d]; d -= (d & (-d)); } return ret;}void solve(int x, int d){ int i = qlast[x]; while (i != 0) { add(q[i].r, q[i].delta); add(q[i].l - 1, -q[i].delta); i = q[i].pre; } ans[x] += getsum(d); while (last[x] != 0) { solve(e[last[x]].y, d + 1); last[x] = e[last[x]].pre; } i = qlast[x]; while (i != 0) { add(q[i].r, -q[i].delta); add(q[i].l - 1, q[i].delta); i = q[i].pre; }}int main(){ int T; freopen("E:\\练习\\testForVS2012\\test\\test\\in.txt","r",stdin); scanf("%d", &T); for (int tt = 1; tt <= T; ++tt) { for (int i = 1; i <= n; ++i) { t[i] = 0; ans[i] = 0; qlast[i] = 0; last[i] = 0; } scanf("%d", &n); for (int i = 2; i <= n; ++i) { int p; scanf("%d", &p); e[i].y = i; e[i].pre = last[p]; last[p] = i; } int Q; scanf("%d", &Q); for (int i = 1; i <= Q; ++i) { int x; scanf("%d%d%d%d", &x, &q[i].l, &q[i].r, &q[i].delta); q[i].pre = qlast[x]; qlast[x] = i; } solve(1, 1); printf("Case %d: ", tt); int magic = 12347; hash1 = 0; for (int i = 1; i <= n; ++i) { hash1 = (hash1 * magic + ans[i]) % MOD; } cout << hash1 << endl; } return 0;}
- 编程之美初赛第一场 树
- 编程之美初赛第一场 树
- 编程之美初赛第一场--树
- 编程之美初赛第一场 树
- 编程之美初赛第一场 树
- 编程之美 初赛第一场 竞价
- 编程之美初赛第一场 焦距
- 编程之美初赛第一场 活动中心
- 编程之美初赛第一场 焦距
- 编程之美初赛第一场 活动中心
- 2014编程之美初赛第一场
- 编程之美初赛第一场
- 编程之美(初赛第一场)
- 编程之美初赛第一场--焦距
- 编程之美初赛第一场 活动中心
- 编程之美初赛第一场_2014
- 编程之美初赛第一场
- 编程之美 2014 初赛第一场
- POJ 1002 487-3279
- 序列化与反序列化
- SDN和NFV中的一些概念
- 数据结构和算法之:图的深度优先和广度优先遍历及其Java实现
- Linux中C语言编程如何使用bool
- 编程之美初赛第一场 树
- 指针和数组(c++primer)
- leetcode第一刷_Insertion Sort List
- Android消息机制之Looper和Handler
- Android如何防止apk程序被反编译
- error C2440: 'static_cast' : cannot convert from 'void (__thiscall CChatDlg::* )(WPARAM,LPARAM)' to
- 关于DatePickerDialog点击返回键取消调用回调方法onDateSet()的解
- CRF-条件随机场
- 冯东阳:解读纯文本链接到底算不算外链