题意:
给予一颗树,最开始点权为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;
}
京公网安备 11010502036488号