牛客网练习赛6(B):
链接: https://www.nowcoder.com/acm/contest/26/B
思路:
因为m的大小为1e7,那么怎么做到O(1)的维护节点的儿子和父亲的信息;
fa[x]表示x的父亲的编号;
用一个sum[x]数组记录节点x的所有儿子节点的权值;
用一个cnt[x]数组表示当前 x节点出现的次数;
dep[x]表示x节点的儿子的个数,即出度;
arr[x]为x节点的权值;
那么,对于每次的的询问,维护
arr[x]++;
cnt[x]++;
sum[x] += dep[x];
sum[x] %= mod;
arr[fa[x]]++;
sum[fa[x]]++;
sum[fa[fa[x]]]++;
那么每次的ans:
ans儿子:sum[x];
ans自己:arr[x]+cnt[fa[x]]];
ans父亲:arr[fa[x]]+cnt[fa[fa[x]]];
ans = ans儿子+ans自己+ans父亲;
code:
#include<bits/stdc++.h>
using namespace std;
typedef int INT;
const int maxn = 1e5 + 99;
const int mod = 19260817;
int fa[maxn];
int arr[maxn];
int sum[maxn];
int dep[maxn];
int cnt[maxn];
inline bool in(int &ret)
{
char ch;
bool sgn = false;//正数
ret = 0;
if ((ch = getchar()) == EOF)
return false;//EOF
while (ch != '-' && (ch<'0' || ch>'9'))
ch = getchar();
if (ch == '-') sgn = true;//负数
else ret = ch - '0';
while (ch = getchar(), ch >= '0'&&ch <= '9')
ret = ret * 10 + ch - '0';
if (sgn) ret = -ret;
return true;//当前输入结束
}
INT main()
{
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i < n; ++i)
{
int x;
in(x);
fa[i + 1] = x;
dep[x]++;
}
int Hash = 0;
int i = 1;
fa[1] = 0;
while (m--)
{
int ans = 0, x;
in(x);
arr[x]++;
cnt[x]++;
sum[x] += dep[x];
sum[x] %= mod;
arr[fa[x]]++;
sum[fa[x]]++;
sum[fa[fa[x]]]++;
sum[0] = 0; cnt[0] = 0; arr[0] = 0;//这个不要漏了,防止x的父亲为0的情况;
ans = (arr[x] + arr[fa[x]] + sum[x] + cnt[fa[x]] + cnt[fa[fa[x]]]) % mod;
Hash = (Hash + (long long)ans*i%mod) % mod;
i++;
}
printf("%d\n", Hash);
return 0;
}
END