时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 131072K,其他语言262144K 64bit IO Format: %lld
题目描述
给你一棵树,最开始点权为0,每次将与一个点x树上距离<=1的所有点点权+1,之后询问这些点修改后的点权和.
输入描述:
第一行两个数n和m
第二行n-1个数,第i个数fa[i + 1]表示i + 1点的父亲编号,保证fa[i + 1]<i + 1
第三行m个数,每个数x依次表示这次操作的点是x
输出描述:
输出一个数,即这m次操作的答案的hash值
如果是第i次操作,这次操作结果为ans,则这个hash值加上
i * ans
输出hash值对19260817取模的结果
示例1
输入
复制
6 3 1 1 2 3 3 1 2 3
输出
复制
34
示例2
输入
复制
6 10 1 1 2 3 3 1 4 6 5 2 3 3 3 3 3
输出
复制
869
备注:
n <= 100000
m <= 10000000
题解:
吐槽一下,题意说的不明确,搞的我一阵子以为自己读错了
hash值+=i*ans,而ans等于点权+1后,与点x树上距离<=1的所有点权和
样例中最后答案就是:3 * 1+5 * 2+7 * 3=34
根据题意,当影响一个点x后,x本身,x的父亲,x的儿子,都会受到影响
int fa[x];//父亲节点
int now[x],son[x],grandson[x];//分别表示当前点被操作次数,当前点的孩子节点操作次数,当前点的孙子节点操作次数
int kid[x];//x的儿子节点有多少个
为啥要用当前点的儿子和孙子节点,我是这么理解的,因为每个点的父亲节点是唯一的,一旦确定点x,其父亲节点,祖父节点都可以确定,而一个点有未知个儿子节点,所以用kid来记录儿子节点的数量。
最后计算x的贡献其实是x本身,x的父亲,x的儿子三个贡献和:
x的父亲:now[fa[x]]+son[fa[x]]+now[fa[fa[x]]]
x的父亲节点的点权受x的父亲节点本身,x节点以及x的父亲的父亲节点
x本身:now[fa[x]]+now[x]+son[x]
x的孩子:kid[x]*now[x]+son[x]+grandson[x]
代码:
代码只过了70%,我也没找到哪里错了,愁。。
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> #define maxn 10000008 const int mod=19260817; typedef long long ll; using namespace std; int fa[maxn]; int now[maxn],son[maxn],grandson[maxn]; int kid[maxn]; int main(){ int n,m; cin>>n>>m; for(int i=2;i<=n;i++) { int x; cin>>x; fa[i]=x; kid[x]++; } ll sum=0; for(int i=1;i<=m;i++) { int x; cin>>x; now[x]=(now[x]+1)%mod; if(fa[x])son[fa[x]]++; if(fa[fa[x]])grandson[fa[fa[x]]]++; int f=(now[fa[x]]+son[fa[x]]+now[fa[fa[x]]])%mod; int m=(now[fa[x]]+now[x]+son[x])%mod; int s=(kid[x]*now[x]%mod+son[x]+grandson[x])%mod; ll ans=(f+m+s)%mod; sum=(sum+ans*i)%mod; } cout<<sum%mod; return 0; }