点权和

点权和

https://ac.nowcoder.com/acm/problem/14393

每次询问一个点,会让当前节点和父亲节点和儿子节点+1,而父亲节点和儿子节点受到影响之后,也会让祖父节点和孙子节点受到影响,所以我们用三个数组受到影响的次数来进行计算。
定义a,b,c分别表示当前节点+1的次数,儿子节点+1的次数,孙子节点+1的次数。
而父亲节点和祖父节点我们可以用fa[]来表示。
每次询问之后,当前节点造成的影响就是:
a[i]+b[i]+a[fa[i]] 自己节点的次数+儿子节点的次数+父亲节点的次数
对于父亲节点,造成的影响是:
a[fa[i]]+b[fa[i]]+a[fa[fa[i]]] 父亲节点的次数+父亲的儿子节点的次数+祖父节点的次数
而儿子节点的贡献是:
b[i]+c[i]+sizes[i]*a[i] 儿子节点的次数+孙子节点的次数+当前节点对sizes[i]个儿子的影响

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <stack>
#include <queue>
#include <cmath>
#define ll long long
#define pi 3.1415927
#define inf 0x3f3f3f3f
#define mod 1000000007
using namespace std;
#define _int __int128_t
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=getchar();
    return f*x;
}
void print(int x)
{
    if(x < 0) {putchar('-');x = -x;}
    if(x/10) print(x/10);
    putchar(x%10+'0');
}
ll n,m,fa[100005],a[100005],b[100005],c[100005],sizes[100005];
int main ()
{
    ll T,i,t,j,k,p,sum=0;
    cin>>n>>m;
    for(i=2;i<=n;++i){
        p=read();
        sizes[p]++;
        fa[i]=p;
    }
    ll x,y,z;
    for(j=1;j<=m;++j){
        i=read();
        a[i]++;
        if(fa[i]) b[fa[i]]++;
        if(fa[fa[i]]) c[fa[fa[i]]]++;

        x=(a[i]+b[i]+a[fa[i]])%19260817; //自己的贡献
        y=(a[fa[i]]+b[fa[i]]+a[fa[fa[i]]])%19260817; //父节点贡献
        z=(b[i]+c[i]+sizes[i]*a[i]%19260817)%19260817;//儿子节点贡献
        ll res=(x+y+z)%19260817;
        sum=(sum+res*j%19260817)%19260817;
    }
    cout<<sum<<endl;

    return 0;
}
全部评论

相关推荐

小红书 后端开发 总包n+8w+期权
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务