noip模拟赛 赤の夜
题目背景
下发压缩包链接: https://pan.baidu.com/s/1geC4ooz 密码: 3vpt(同T1)
正在想这么说的时候——
突然涌出一种强烈的晕眩感。
这是,什么……?
眼花吗?不对……
由佳也失去平衡快摔倒了。
连平常的呼吸都难以保持。
这时——空间更大幅度的扭曲了。
这种感觉,就像失去了身体和空间的境界线,渐渐,渐渐的被扭曲着……
昏过去,也只是时间的……问题……罢了……
————?
感觉到——有什么发生了崩坏?
这是……什么?
这到底是,怎么回事……?
赤夜——
照亮了我们,不,照亮了整条街道。
本应悬挂在西边的天空的夕阳……不见了?
我条件反射地抬头仰望天穹。
啊啊啊啊啊——!!!
目睹了不可能存在的景色,我不禁大声喊叫起来……
在我们头顶上的,那是……
漆黑——漆黑之月
比黄昏更为黑暗,应该被称为“赤夜”的世界,在我们的周围蔓延。
题目描述
数据结构大师ddd给你出了一道题:
给你一棵树,最开始点权为0,每次将与一个点x树上距离<=1的所有点点权+1,之后询问这些点修改后的点权和
输入输出格式
输入输出格式
输入格式:
第一行两个数n和m
之后一行n-1个数,第i个数fa[i + 1]表示i + 1点的父亲编号,保证fa[i + 1]<i + 1
之后一行m个数,每个数x依次表示这次操作的点是x
输出格式:
输出一个数,即这m次询问的答案的和
保证答案在有符号64位整数范围内
输入输出样例
6 3 1 1 2 3 3 1 2 3
15
6 10 1 1 2 3 3 1 4 6 5 2 3 3 3 3 3
115
说明
样例#3,#4,#5,#6见下发的文件
【子任务】
子任务会给出部分测试数据的特点。
如果你在解决题目中遇到了困难, 可以尝试只解决一部分测试数据。
每个测试点的数据规模及特点如下表:
测试点编号 | n的范围 | m的范围 | 特殊性质 |
---|---|---|---|
测试点1 | n = 1000 | m = 1000 | 数据随机 |
测试点2 | n = 1000 | m = 1000 | 数据随机 |
测试点3 | n = 100000 | m = 100000 | |
测试点4 | n = 100000 | m = 100000 | |
测试点5 | n = 100000 | m = 1000000 | 树是一条链 |
测试点6 | n = 100000 | m = 1000000 | |
测试点7 | n = 100000 | m = 1000000 | |
测试点8 | n = 100000 | m = 3000000 | |
测试点9 | n = 100000 | m = 3000000 | |
测试点10 | n = 100000 | m = 10000000 |
【由乃暖心的小提示】
由于这个题最大读入量有约45MB,非常巨大,顺便为了教你们怎么写读入优化,在这里附送上一个fread膜版,在下发文件中。(真正NOIP的时候如果你记得住可以用的,或许就是AK和595的差别哦~)
【说明】
【样例1说明】
原树结构:
第一次操作后:
这次操作的答案为1+1+1=3
第二次操作后:
这次操作的答案为2+2+1=5
第三次操作后:
这次操作的答案为3+2+1+1=7
所有操作的答案总和为3+5+7=15,故输出15.
分析:一类修改+查询问题.m高达10000000,显然不能直接操作,而由于它每次操作都是一个点对多个点产生贡献,每次也是查询一些点,我们就可以计算每个点对答案的贡献,不用实际操作,打上标记就好了.
如果当前操作的点是x,那么x的答案就+=x所连的点+1,对x的父亲的贡献是2(x+1,fa[x] + 1),对x的父亲的父亲的贡献是1,对x的儿子的贡献是2,对x的儿子的儿子的贡献是1.枚举每个点的儿子是很费时间的,所以我们只记录父节点和父节点的父节点的贡献,就能推出当前的答案.
维护两个数组:pushup,tag,son,tag表示是操作的次数,pushup是其它点对当前点的贡献和,son是当前点的子节点一共修改了多少次.修改点x:
tag[x]++,pushup[fa[x]] +=2,pushup[fa[fa[x]]]++,son[fa[x]]++,pushup[x] += du[x] + 1.
查询点x:
ans = pushup[x] + tag[fa[x]] * 2 + tag[fa[fa[x]]] + son[fa[x]] - tag[x].
(子节点对x的贡献+父节点的贡献+父节点的父节点的贡献+和x同一深度其它点的贡献).
当操作很费事,并且操作对询问有影响时,可以试试能不能对操作打个标记而不去实际操作来计算对答案的贡献.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n, m; int fa[100010]; long long ans, tag[100010], pushup[100010], son[100010], du[100010]; long long read() { long long res = 0; char ch = 0; while (ch < '0' || ch > '9') ch = getchar(); while (ch >= '0' && ch <= '9') { res = res * 10 + ch - '0'; ch = getchar(); } return res; } int main() { n = read(); m = read(); for (int i = 2; i <= n; i++) { fa[i] = read(); du[i]++; du[fa[i]]++; } while (m--) { long long x; x = read(); pushup[x] += du[x] + 1; pushup[fa[x]] += 2; pushup[fa[fa[x]]]++; tag[x]++; son[fa[x]]++; long long temp = pushup[x]; temp += tag[fa[x]] * 2; temp += tag[fa[fa[x]]]; temp += son[fa[x]] - tag[x]; ans += temp; } printf("%lld\n", ans); return 0; }