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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值