点权和(树形结构思维)

点权和(树形结构思维)

题意:

给你一棵树,最开始点权为0,每次将与一个点x树上距离<=1的所有点点权+1,之后询问这些点修改后的点权和.输出一个数,即这m次操作的答案的hash值。如果是第i次操作,这次操作结果为ans,则这个hash值加上i * ans输出hash值对19260817取模的结果

n <= 100000
m <= 10000000

思路:
因为m很大所以,又在线,所以需要O(1)处理每次。那么这题的突破口就是树上距离小于等于1的点,可以从每个点影响周围点的贡献入手。 一个点无非就是影响他的儿子,他的父亲,他自己。
所以只要把 这个点父亲节点的贡献+这个点儿子节点的贡献+这个点本身的贡献 就完事了
定义数组 now[x] 表示节点x被操作的次数
son[x] 表示节点x的儿子被操作的次数
b[x] 表示节点x的孙子被操作的次数 为什么要孙子,因为在处理儿子节点的贡献时,孙子节点对儿子节点会产生影响的。
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
const ll mod=19260817;
const int N=1e5+5;
int n,m,fa[N];//表示当前节点的父亲节点是谁
ll siz[N];//表示当前节点儿子的数量
ll son[N];//表示儿子节点被操作的次数
ll sson[N];//表示孙子节点被操作的次数
ll now[N];//表示当前节点被操作的次数
ll ans;
int main(){
	scanf("%d%d",&n,&m);
	for(int i=2,x;i<=n;i++){
		scanf("%d",&x);
		fa[i]=x;
		siz[x]++;
	}
	for(int i=1,x;i<=m;i++){
		scanf("%d",&x);
		now[x]++;//更新 
		if(fa[x])son[fa[x]]++;
		if(fa[fa[x]])sson[fa[fa[x]]]++;
		ll k=0;
		k=(now[x]+now[fa[x]])%mod+son[x];//自己的贡献 
		k%=mod;
		k+=(now[fa[x]]+son[fa[x]]+now[fa[fa[x]]])%mod;//父亲的贡献 
		k%=mod;
		k+=(siz[x]*now[x]%mod+son[x]+sson[x])%mod;//所有儿子的贡献 
		k%=mod;
		ans=(ans+k*i%mod)%mod;
	}
	printf("%lld",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值