这种题肯定不会是暴力枚举,多半考虑是贡献
首先我们要想清楚的是,我每次操作,会对哪些节点产生影响,答案又是从哪些节点更新而来
很显然我们会从儿子,自身,父亲这三个角度去思考问题。
所以我们会设计状态 now[]表示自身被操作的次数,a[],表示被儿子影响的次数,b[]表示的是被孙子操作的次数,in[]表示的是儿子个数。
为什么这里会出现孙子呢,因为孙子+1,儿子+1,那么当答案的时候,儿子的值变化了,所以答案也变化了。
为什么不用专门设计父亲呢?因为所有的父亲都是别人的儿子,所以这样的状态足以,不然就更加复杂了。
假如我们对当前点进行更新,那么我们可以更新:
当前点的权值,别的点的儿子影响,孙子影响。
具体解释看代码,很多不同的答案都是对的,只要能表达清楚就行
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<map> using namespace std; typedef long long ll; const int N=1e5+5; const int mod=19260817; ll p[N],a[N],b[N]; ll in[N]; ll now[N]; int main(){ int n,m; cin>>n>>m; int i; for(i=2;i<=n;i++){ int x; scanf("%d",&x); in[x]++; p[i]=x; } ll res=0; for(i=1;i<=m;i++){ int x; scanf("%d",&x); now[x]++;//当前操作+1 ll ans=0; if(p[x]){ ll t=p[x]; a[t]++;//父亲被自己影响+1 ans=(ans+now[t]*2ll+a[t])%mod;//父亲的操作要×2,因为父亲和自己都加了1,再加上父亲被自己影响的次数 } if(p[p[x]]){ ll t=p[p[x]]; ans=(ans+now[t])%mod;//爷爷的操作影响 b[t]++;//爷爷被自己的影响 } ans=(ans+(in[x]+1)%mod*now[x]%mod+a[x]*2+b[x])%mod;//自己操作数的贡献,以及儿子对儿子和自己的贡献以及孙子的贡献 res=(res+ans*i+mod)%mod; } cout<<res<<endl; return 0; }