P9208 虚人「无」

Question 问题 P9208 虚人「无」

给定二元序列 { ( v i , c i ) } \{(v_i,c_i)\} {(vi,ci)} 和一棵以 1 1 1 为根的有根树。第 i i i 个点的点权是 ( v i , c i ) (v_i,c_i) (vi,ci)。

  • 定义一个非根节点的权值为其子树内的 c c c 的积乘上其子树补的 v v v 的积。
  • 定义一个根节点的权值为其子树内的 c c c 的积。

形式化的讲,若 u u u 不为根节点,则 u u u 的权值 f u f_u fu 为:

f u = ∏ v ∈ substree ⁡ ( u ) c v × ∏ v ∉ substree ⁡ ( u ) v v f_u=\prod\limits_{v\in \operatorname{substree}(u)} c_v\times \prod\limits_{v\notin \operatorname{substree}(u)} v_v fu=v∈substree(u)∏cv×v∈/substree(u)∏vv

否则,其权值 f u f_u fu 为:

f u = ∏ v = 1 n c v f_u=\prod\limits_{v=1}^n c_v fu=v=1∏ncv

试求整棵树所有节点的权值之和 ,答案对 m m m 取模。请注意:保证 m \bm m m 是质数

Analysis 分析

定义:

d f n x dfn_x dfnx 为 x x x 的 d f s dfs dfs 序。

s i z x siz_x sizx 为 x x x 的子树大小。

先讲正解:dfs 序 & 线段树查询

我们跑一遍 d f s dfs dfs 序之后,思考对于一个点 x x x,其子节点所在的 d f s dfs dfs 序必然在区间 d f n x ∼ d f n x + s i z x − 1 dfn_{x} \sim dfn_{x}+siz_{x}-1 dfnx∼dfnx+sizx−1 之中。

接下来我们只需要维护区间内 c , v c,v c,v 的乘积,显然我们只需要用线段树维护一下乘积就行了。

以下是错解:逆元(可选择不看)

考虑一个非常自然就能想到的方法,看到取模,想用逆元。但是在本题不行。因为使用逆元需要当所有参与计算答案的值均存在逆元,即模数 m ⊥ c i , v i m \perp c_i,v_i m⊥ci,vi。

所以这道题可以通过特殊构造卡掉逆元做法。

Code 代码

cpp 复制代码
#include<bits/stdc++.h>
#define rint register int
#define ls (p<<1)
#define rs (p<<1|1)
using namespace std;
typedef long long ll;
const int N=3e5+8;
int n,x,y,tot,cnt,mod;
int head[N],siz[N],dfn[N];
ll c[N],v[N],ans;
struct edge{
	int nxt,to;
}e[N<<1];
struct tree{
	int l,r;
	ll csum,vsum;
	#define l(p) t[p].l
	#define r(p) t[p].r
	#define cs(p) t[p].csum
	#define vs(p) t[p].vsum
}t[N<<2];
inline void add(int a,int b){e[++tot]={head[a],b};head[a]=tot;}
inline void add(int a,int b,string s){add(a,b);add(b,a);}
inline void dfs(int x,int fa){
	siz[x]=1;dfn[x]=++cnt;
	for(rint i=head[x];i;i=e[i].nxt){
		int y=e[i].to;
		if(y!=fa){
			dfs(y,x);
			siz[x]+=siz[y];
		}
	}
}
void build(int p,int l,int r){
	l(p)=l;r(p)=r;
	if(l==r){cs(p)=c[l],vs(p)=v[l];return;}
	int Mid=l+r>>1;
	build(ls,l,Mid),build(rs,Mid+1,r);
	cs(p)=cs(ls)*cs(rs)%mod;
	vs(p)=vs(ls)*vs(rs)%mod;
	return ;
}
ll query(int p,int l,int r,int cmd){
	if(l<=l(p)&&r(p)<=r){
		if(cmd) return vs(p);
		else return cs(p);
	}
	ll res=1;int Mid=l(p)+r(p)>>1;
	if(l<=Mid) res=query(ls,l,r,cmd);
	if(r>Mid) res=res*query(rs,l,r,cmd)%mod;
	return res;
}
int main(){
	read(n,mod);
	for(rint i=1;i<n;i++) read(x,y),add(x,y,"Mr.Az");
	dfs(1,0);
	for(rint i=1;i<=n;i++) read(c[dfn[i]]);
	for(rint i=1;i<=n;i++) read(v[dfn[i]]);
	build(1,1,n);
	for(rint i=1;i<=n;i++){
		ll res=1;
		if(dfn[i]!=1) res=query(1,1,dfn[i]-1,1);
		res=res*query(1,dfn[i],dfn[i]+siz[i]-1,0)%mod;
		if(dfn[i]+siz[i]<=n) res=res*query(1,dfn[i]+siz[i],n,1)%mod;
		ans=(ans+res)%mod;
	}
	printf("%lld\n",ans);
    return 0;
}
相关推荐
希望有朝一日能如愿以偿23 分钟前
力扣题解(飞机座位分配概率)
算法·leetcode·职场和发展
丶Darling.35 分钟前
代码随想录 | Day26 | 二叉树:二叉搜索树中的插入操作&&删除二叉搜索树中的节点&&修剪二叉搜索树
开发语言·数据结构·c++·笔记·学习·算法
JustCouvrir39 分钟前
代码随想录算法训练营Day15
算法
小小工匠1 小时前
加密与安全_HOTP一次性密码生成算法
算法·安全·htop·一次性密码
中文英文-我选中文1 小时前
排序算法的理解
算法·排序算法
我明天再来学Web渗透1 小时前
【hot100-java】【二叉树的层序遍历】
java·开发语言·数据库·sql·算法·排序算法
数据分析螺丝钉2 小时前
力扣第240题“搜索二维矩阵 II”
经验分享·python·算法·leetcode·面试
no_play_no_games2 小时前
「3.3」虫洞 Wormholes
数据结构·c++·算法·图论
五味香2 小时前
C++学习,信号处理
android·c语言·开发语言·c++·学习·算法·信号处理
毕小宝2 小时前
逻辑回归(下): Sigmoid 函数的发展历史
算法·机器学习·逻辑回归