Description
给你一棵树,最开始点权为000,每次将与一个点xxx树上距离≤1\le 1≤1的所有点点权+1+1+1,之后询问这些点修改后的点权和.
Input
第一行两个数nnn和mmm
第二行n−1n-1n−1个数,第iii个数fa[i+1]fa[i + 1]fa[i+1]表示i+1i + 1i+1点的父亲编号,保证fa[i+1]<i+1fa[i + 1]<i + 1fa[i+1]<i+1
第三行mmm个数,每个数xxx次表示这次操作的点是xxx
(n≤105,m≤106)(n\le 10^5,m\le 10^6)(n≤105,m≤106)
Output
输出一个数,即这mmm次操作的答案的hashhashhash值
如果是第iii次操作,这次操作结果为ansansans,则这个hashhashhash值加上i⋅ansi\cdot ansi⋅ans
输出hashhashhash值对192608171926081719260817取模的结果
Sample Input
6 3
1 1 2 3 3
1 2 3
Sample Output
34
Solution
查询一点uuu的答案分为以下
1.由于uuu被操作cnt[u]cnt[u]cnt[u]次使得uuu以及uuu的所有邻接点答案加一,该部分贡献为cnt[u]⋅(du[u]+1)cnt[u]\cdot (du[u]+1)cnt[u]⋅(du[u]+1)
2.由于uuu的父亲被操作cnt[fa[u]]cnt[fa[u]]cnt[fa[u]]次,使得uuu和fa[u]fa[u]fa[u]答案都加一,该部分贡献为2⋅cnt[fa[u]]2\cdot cnt[fa[u]]2⋅cnt[fa[u]]
3.由于uuu的爷爷被操作cnt[fa[fa[u]]]cnt[fa[fa[u]]]cnt[fa[fa[u]]]次,使得fa[u]fa[u]fa[u]答案加一,该部分贡献为cnt[fa[fa[u]]]cnt[fa[fa[u]]]cnt[fa[fa[u]]]
4.由于uuu的兄弟被操作scnt[fa[u]]−cnt[u]scnt[fa[u]]-cnt[u]scnt[fa[u]]−cnt[u]次,使得fa[u]fa[u]fa[u]答案加上该部分,该部分贡献scnt[fa[u]]−cnt[u]scnt[fa[u]]-cnt[u]scnt[fa[u]]−cnt[u],其中scnt[fa[u]]scnt[fa[u]]scnt[fa[u]]表示fa[u]fa[u]fa[u]的儿子们被操作的次数之和
5.由于uuu的儿子被操作使得uuu的答案加上对应值,此部分可以在其儿子被操作时直接累加到uuu的答案上
对uuu点操作一次的影响为
1.对uuu父亲的影响,使得fa[u]fa[u]fa[u]的答案加二
2.对uuu爷爷的影响,使得fa[fa[u]]fa[fa[u]]fa[fa[u]]的答案加一
故只需要维护cnt[u],scnt[u]cnt[u],scnt[u]cnt[u],scnt[u]以及统计答案的ans[u]ans[u]ans[u]即可,时间复杂度O(n+m)O(n+m)O(n+m)
Code
#include<cstdio>
using namespace std;
typedef long long ll;
const int maxn=100005;
#define mod 19260817
int add(int x,int y)
{
x+=y;
if(x>=mod)x-=mod;
return x;
}
int mul(int x,int y)
{
ll z=1ll*x*y;
return z-z/mod*mod;
}
int n,m,f[maxn],du[maxn],cnt[maxn],scnt[maxn],ans[maxn];
int main()
{
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++)scanf("%d",&f[i]),du[i]++,du[f[i]]++;
int sum=0;
for(int i=1;i<=m;i++)
{
int u,res=0;
scanf("%d",&u);
ans[u]=add(ans[u],du[u]+1);
if(f[u])ans[f[u]]=add(ans[f[u]],2),scnt[f[u]]=add(scnt[f[u]],1);
if(f[f[u]])ans[f[f[u]]]=add(ans[f[f[u]]],1);
cnt[u]=add(cnt[u],1);
if(f[u])
{
res=add(res,mul(2,cnt[f[u]]));
res=add(res,add(scnt[f[u]],mod-cnt[u]));
}
if(f[f[u]])res=add(res,cnt[f[f[u]]]);
res=add(res,ans[u]);
sum=add(sum,mul(i,res));
}
printf("%d\n",sum);
return 0;
}