nowcode练习赛6(B):点权和

来源:互联网 发布:seo关键词的布局原则 编辑:程序博客网 时间:2024/06/05 10:22

牛客网练习赛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