题意:
给予一颗树,最开始点权为0,每次将与一个点x树上距离<=1的所有点点权+1,之后询问这些点修改后的点权和(与点x树上距离<=1的所有点点权之和).如果是第i次操作,这次操作结果为ans,则这个结果的值加上
i * ans,结果模19260817。
思路:
设数组f1[]记录该点本身修改的次数,数组f2[]记录该点儿子的修改次数,数组f3[]记录该点孙子的修改次数。
该点v的点权= f1[v] (本身修改次数) + f1[parent[v]] (父亲修改次数) +f2[v] (儿子修改次数)
该点父亲的点权=f1[parent[v]] (父亲修改次数) + f1[parent[parent[v]]] (爷爷修改次数) + f2[parent[v]] (父亲儿子的修改次数)
该点儿子的点权和=f1[v] * child[v] (本身修改次数*儿子个数) + f2[v] (儿子的修改次数) + f3[v] (孙子修改的次数)
代码:
#include <bits/stdc++.h> #define inf 19260817 using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char c=getchar(); while(c<'0'||c>'9') { if(c=='-') { f=-f; } c=getchar(); } while(c>='0'&&c<='9') { x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return f*x; } int parent[100005]; int child[100005]; ll sum[100005], f1[100005], f2[100005], f3[100005]; void fun(int v,int k) { f1[v]++; if(v!=1) f2[parent[v]]++; if(parent[v]!=1) f3[parent[parent[v]]]++; } ll result(int v) { ll z=(f1[v]+f1[parent[v]]+f2[v])%inf; z=(z+f1[parent[v]]+f1[parent[parent[v]]]+f2[parent[v]])%inf; z=(z+f1[v]*child[v]%inf+f2[v]+f3[v])%inf; return z; } int main() { int n, m; n=read(); m=read(); for(int i=2; i<=n; i++) { int v; v=read(); parent[i]=v; child[v]++; } ll ans=0; for(int i=1; i<=m; i++) { int v; v=read(); fun(v,0); ll z=result(v); ans=(ans+(z*i)%inf)%inf; } cout << ans << endl; return 0; }