时间限制: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;
}