题目描述

给你一棵树,最开始点权为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取模的结果

题解

对于本题,数据范围太大,没办法进行暴力,我们考虑谁对当前点有贡献。

对于一个点,对他有贡献的点就是他自己,他的父亲和他的儿子。

对于他自己和他父亲的贡献,我们很好维护。对于自己,我们维护一个数组,表示i点被操作的个数;对于父亲,我们维护一个数组,表示i结点的父亲,那对于某节点父亲的贡献就是

比较棘手的是维护儿子。我们没办法直观的得到儿子节点的编号,那我们换一种方式,维护一个数组,表示父亲节点为i的节点被操作的次数。在我们每得到一个要被操作的节点时,我们只需要对进行加一就可以轻松的维护儿子信息。

假设我们现在要做操作的是节点,那么x的父亲节点的权值为,其中表示x父节点被操作的次数,表示x父节点的父节点被操作的次数,表示以x的父节点为父节点的儿子被操作的次数。

那么x本身的权值同理,为,其中表示x被操作的次数,表示x父节点被操作的次数,表示以x为父节点的儿子被操作的次数。

对于x的儿子,比较棘手。其一因为我们没办法获得x儿子的儿子,我们仿照之前的解决方法,再维护一个数组,表示以i为爷爷的结点被操作的次数,同理,在我们每得到一个要被操作的节点时,我们只需要对进行加一就可以维护孙子信息。其二是因为此时x的儿子不只是一个,所以其父亲对于他的贡献不再单单是被操作次数,而应该还要乘上此时儿子的数量,这个问题很好解决,我们只需要设置一个siz数组,在输入父节点时同时维护了fa数组和siz数组就可以啦。

那么现在我们就可以算x的儿子的权值了,,其中表示x对他儿子的贡献,表示以x的儿子被操作的次数,表示x的儿子节点的儿子节点被操作的次数。

所以操作x之后的被修改的节点的权值和就是father+itself+son了,然后我们按照题干的要求计算hash值就好啦

代码

#include<iostream>
#include<algorithm>
#include<map>
#include<vector>
#include<set>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pb push_back
#define pii pair<int,int>
#define all(A) A.begin(), A.end()
#define fi first
#define se second
#define MP make_pair
#define rep(i,n) for(register int i=0;i<(n);++i)
#define repi(i,a,b) for(register int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(register int i=int(b);i>=(a);--i)
template<typename T>
inline T read(){
    T s=0,f=1; char ch = getchar();
    while(!isdigit(ch)) {if(ch == '-') f=-1;ch = getchar();}
    while(isdigit(ch)) {s=(s<<3)+(s<<1)+ch-48;ch = getchar();}
    return s*f;
}
#define gn() read<int>()
#define gl() read<ll>()
template<typename T>
inline void print(T x) {
    if(x<0) putchar('-'), x=-x;
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
////////////////////////////////////////////////////////////////////////
const int N=1e5+100;
int fa[N];
ll it[N],son[N],gson[N],siz[N];
const int mod=19260817;
int n,m;
////////////////////////////////////////////////////////////////////////
int main(){
    n=gn(),m=gn();
    for(int i=2;i<=n;++i){
        fa[i]=gn();
        siz[fa[i]]++;
    }
    ll ans=0;
    for(int cnt=1;cnt<=m;++cnt){
        int i=gn();
        ++it[i];
        if(fa[i])++son[fa[i]];
        if(fa[fa[i]])++gson[fa[fa[i]]];
        ll d=0;
        d=(d+(it[fa[i]]+it[fa[fa[i]]]+son[fa[i]])%mod)%mod;
        d=(d+(it[i]+it[fa[i]]+son[i])%mod)%mod;
        d=(d+(siz[i]%mod*it[i]%mod+son[i]+gson[i])%mod)%mod;
        ans=(ans+d*cnt%mod)%mod;
    }
    print(ans%mod);
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/