Codeforces 434E - Furukawa Nagisa's Tree(三元环+点分治)
场号 hopping,刚好是我的学号(指 round 的编号)
注:下文中分别用 \(X,Y,K\) 代替题目中的 \(x,y,k\)
注意到这东西长得有点像三元环,因此考虑往三元环方面考虑。我们重新建立一张图,对于两点 \(x,y\),如果 \(x\to y\) 路径对应的权值为 \(X\)(即 \(x\to y\) 这条路径属于 Furukawa Nagisa),那么我们就在 \(x\to y\) 之间连一条权值为 \(1\) 的边,否则我们在 \(x\to y\) 之间连一条权值为 \(0\) 的边,那么我们要求的即为有多少个三元组 \((x,y,z)\),满足 \(x\to y,y\to z,x\to z\) 之间全是权值为 \(1\) 的边,或者全是权值为 \(0\) 的边。我们考虑借鉴竞赛图三元环计数的一个小 trick:从反面考虑。具体来说我们考虑不合法的情况长什么样,不难发现,对于每种不合法的情况都恰好有两个点,满足与它相连的两条边恰好一条权值为 \(0\),一条权值为 \(1\)。我们记这样的点为这个三元组的“代表点”。我们考虑对每个点分别统计有多少个三元组,满足其在该三元组中作为一个代表点出现,那么一个不合法的三元组会恰好被计算两次,因此将这个数目除以 \(2\) 就是不合法的三元组个数。
那么怎么计算每个点在多少个三元组中作为代表点呢?注意到对于一个点 \(x\) 而言,与其相连的点可以被分为四类:\(y\to x\),权值为 \(0/1\),\(x\to y\),权值为 \(0/1\)。因此考虑将与 \(x\) 相连的两条边,一条权值为 \(0\),一条权值为 \(1\) 的情况分为以下四类:
- \(y\to x\),权值为 \(0\),\(z\to x\),权值为 \(1\)
- \(y\to x\),权值为 \(0\),\(x\to z\),权值为 \(1\)
- \(x\to y\),权值为 \(0\),\(z\to x\),权值为 \(1\)
- \(x\to y\),权值为 \(0\),\(x\to z\),权值为 \(1\)
不难发现对于第一种和第四种情况,\(y,z\) 之间的边既可以是 \(y\to z\),也可以是 \(z\to x\),因此贡献应该乘 \(2\),而对于第二种和第三种情况,\(y,z\) 之间边的指向唯一。故如果我们已经求出 \(c1_x\) 表示有多少个 \(y\) 满足 \(y\to x\) 的边权值为 \(1\),\(c2_x\) 表示有多少个 \(y\) 满足 \(x\to y\) 的边的权值为 \(1\),那么一个点 \(x\) 的贡献即可写作:
\]
接下来考虑怎样求出 \(c1_x,c2_x\),注意到这里涉及树上路径统计,因此考虑点分治,于是问题可以转化为如何求出经过当前分治中心 \(x\) 的路径的贡献。对于 \(x\) 所在的连通块中的点 \(y\),我们考虑一遍 DFS 找出 \(x\to y\) 路径上所有点 \(x=p_1,p_2,p_3,\cdots,p_k=y\),那么我们考虑设 \(s_y=\sum\limits_{i=2}^ka_{p_i}·K^{k-i},t_y=\sum\limits_{i=1}^ka_{p_i}·K^{i-1}\),那么对于一条 \(u\to v\) 的路径,其权值可以写作 \(s_u+t_v·K^{dep_u}\)。我们考虑从左到右遍历所有子树,那么 \(c1_v\) 会加上满足 \(s_u+t_v·K^{dep_u}\equiv X\pmod{Y}\) 的 \(u\) 的个数,这个可以开一个桶 \(b1\),然后每加入一个点 \(u\) 时,就在 \((X-s_u)·K^{-dep_u}\) 位置加 \(1\),然后通过调用 \(b1_{t_v}\) 即可求出符合要求的 \(u\) 的个数。\(c2_v\) 的贡献也同理,一个点 \(u\) 会对 \(c2_v\) 产生贡献当且仅当 \(s_v+t_u·K^{dep_v}\equiv X\pmod{Y}\),化简可得 \(t_u\equiv(X-s_v)·K^{-dep_u}\pmod{Y}\),同样开个桶 \(b2\) 维护一下即可。
时间复杂度 \(n\log^2n\)
const int MAXN=1e5;
const int INF=0x3f3f3f3f;
int n,X,Y,k,a[MAXN+5];
int hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
int qpow(int x,int e){
int ret=1;
for(;e;e>>=1,x=1ll*x*x%Y) if(e&1) ret=1ll*ret*x%Y;
return ret;
}
int pw[MAXN+5],ipw[MAXN+5];
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int siz[MAXN+5],cent=0,mx[MAXN+5];bool vis[MAXN+5];
void findcent(int x,int f,int tot){
siz[x]=1;mx[x]=0;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
findcent(y,x,tot);siz[x]+=siz[y];
chkmax(mx[x],siz[y]);
} chkmax(mx[x],tot-siz[x]);
if(mx[x]<mx[cent]) cent=x;
}
int dep[MAXN+5],f1[MAXN+5],f2[MAXN+5];
void getdep(int x,int f){
// printf("%d %d %d %d\n",x,dep[x],f1[x],f2[x]);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
dep[y]=dep[x]+1;f1[y]=(1ll*f1[x]*k+a[y])%Y;
f2[y]=(f2[x]+1ll*a[y]*pw[dep[y]])%Y;
getdep(y,x);
}
}
vector<int> pt;
int res1[MAXN+5],res2[MAXN+5];
void getpts(int x,int f){
pt.pb(x);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(y==f||vis[y]) continue;
getpts(y,x);
}
}
void divcent(int x){
// printf("divcent %d\n",x);
vis[x]=1;f1[x]=0;f2[x]=a[x];dep[x]=0;
map<int,int> cnt1,cnt2;
#define insert1(x) cnt1[1ll*(X-f1[x]+Y)*ipw[dep[x]]%Y]++
#define insert2(x) cnt2[f2[x]]++
#define calc(x) (res1[x]+=cnt1[f2[x]],res2[x]+=cnt2[1ll*(X-f1[x]+Y)*ipw[dep[x]]%Y])
insert1(x);insert2(x);stack<int> stk;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(vis[y]) continue;
f1[y]=a[y];f2[y]=(1ll*a[y]*k+a[x])%Y;
dep[y]=1;getdep(y,x);
}
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(vis[y]) continue;
// printf("y=%d\n",y);
pt.clear();getpts(y,x);stk.push(y);
for(int z:pt) calc(z);
for(int z:pt) insert1(z),insert2(z);
} cnt1.clear();cnt2.clear();
while(!stk.empty()){
int y=stk.top();stk.pop();
// printf("y=%d\n",y);
pt.clear();getpts(y,x);
for(int z:pt) calc(z);
for(int z:pt) insert1(z),insert2(z);
} calc(x);
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];if(vis[y]) continue;
cent=0;findcent(y,x,siz[y]);divcent(cent);
}
}
int main(){
scanf("%d%d%d%d",&n,&Y,&k,&X);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),adde(u,v),adde(v,u);
pw[0]=ipw[0]=1;pw[1]=k;ipw[1]=qpow(k,Y-2);
for(int i=2;i<=n;i++){
pw[i]=1ll*pw[i-1]*pw[1]%Y;
ipw[i]=1ll*ipw[i-1]*ipw[1]%Y;
} mx[0]=INF;findcent(1,0,n);divcent(cent);
for(int i=1;i<=n;i++) if(a[i]==X) res1[i]++,res2[i]++;
// for(int i=1;i<=n;i++) printf("%d %d\n",res1[i],res2[i]);
ll res=0;
for(int i=1;i<=n;i++){
int rst1=n-res1[i],rst2=n-res2[i];
res+=2ll*rst1*res1[i];res+=1ll*rst1*res2[i];
res+=1ll*rst2*res1[i];res+=2ll*rst2*res2[i];
} printf("%lld\n",1ll*n*n*n-(res>>1));
return 0;
}
Codeforces 434E - Furukawa Nagisa's Tree(三元环+点分治)的更多相关文章
- 【CF434E】Furukawa Nagisa's Tree 点分治
[CF434E]Furukawa Nagisa's Tree 题意:一棵n个点的树,点有点权.定义$G(a,b)$表示:我们将树上从a走到b经过的点都拿出来,设这些点的点权分别为$z_0,z_1... ...
- Codeforces Gym 100342J Problem J. Triatrip 三元环
题目链接: http://codeforces.com/gym/100342 题意: 求三元环的个数 题解: 用bitset分别统计每个点的出度的边和入度的边. 枚举每一条边(a,b),计算以b为出度 ...
- Codeforces Gym 100342J Problem J. Triatrip 求三元环的数量 bitset
Problem J. Triatrip Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/at ...
- Codeforces Gym 100342J Problem J. Triatrip bitset 求三元环的数量
Problem J. TriatripTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100342/att ...
- Codeforces 985G - Team Players(三元环)
Codeforces 题目传送门 & 洛谷题目传送门 真·ycx 做啥题我就做啥题 考虑枚举 \(j\),我们预处理出 \(c1_i\) 表示与 \(i\) 相连的编号 \(<i\) 的 ...
- BZOJ.5407.girls(容斥 三元环)
题目链接 CF 原题 \(Description\) 有n个点,其中有m条边连接两个点.每一个没有连边的三元组\((i,j,k)(i<j<k)\)对答案的贡献为\(A*i+B*j+C*k\ ...
- BZOJ 3498 PA2009 Cakes(三元环处理)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3498 [题目大意] N个点m条边,每个点有一个点权a. 对于任意一个三元环(j,j,k ...
- HDU 6184 Counting Stars 经典三元环计数
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6184 题意: n个点m条边的无向图,问有多少个A-structure 其中A-structure满足V ...
- BZOJ3498PA2009 Cakes——三元环
题目描述 N个点m条边,每个点有一个点权a.对于任意一个三元环(j,j,k)(i<j<k),它的贡献为max(ai,aj,ak) 求所有三元环的贡献和.N<100000,,m< ...
随机推荐
- Golang通脉之结构体
Go语言中的基础数据类型可以表示一些事物的基本属性,但是要表达一个事物的全部或部分属性时,这时候再用单一的基本数据类型明显就无法满足需求了,Go语言提供了一种自定义数据类型,可以封装多个基本数据类型, ...
- the Agiles Scrum Meeting 5
会议时间:2020.4.13 20:00 1.每个人的工作 今天已完成的工作 增量组:完成了增量开发的基础工作,初步完成了自动评测机制 issues:增量组:准备评测机制,增加仓库自动创建和管理 完善 ...
- 使用nexus搭建一个docker私服
使用nexus搭建docker私服 一.需求: 二.实现步骤 1.编写`docker-compose`文件,实现`nexus`的部署 2.修改/usr/lib/systemd/system/docke ...
- 2021.9.20考试总结[NOIP模拟57]
(换个编辑器代码就SB地不自动折叠了.. T1 2A 考察快读的写法. $code:$ T1 #include<bits/stdc++.h> #define scanf SCANF=sca ...
- 计算机中的contex理解
原文链接 https://www.xuebuyuan.com/2016635.html 1.其实简单的说就是跟当前主题有关的所有内容. 2.如说到程序的上下文,就是当前这段程序之上和之下的程序段.因 ...
- 计算机网络之网络层路由选择协议(自治系统AS、RIP、OSPF、BGP)
文章转自:https://blog.csdn.net/weixin_43914604/article/details/105313629 学习课程:<2019王道考研计算机网络> 学习目的 ...
- 华为HCIP-Eth-trunk原理知识点
Eth-trunk(端口聚合.链路捆绑.链路聚合.以太通道) Eth-trunk技术出现的原因: • 随着网络中部署的业务量不断增长,对于全双工点对点链路,单条物理链路的带宽已不能满足正常的业务流量 ...
- K8S_Kubernetes
Google创造, K8S,是基于容器的集群管理平台, K8S集群 应用场景 微服务 这个集群主要包括两个部分 一个Master节点(主节点) 一群Node节点(计算节点) Master节 ...
- Python3使用Print输出彩色字体
一.介绍 在一些开发程序中,有些输出消息需要突出显示,我们可以尝试着给他们换上更靓丽的颜色来突出显示. 二.实现过程 终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关. ...
- 彻底解决SLF4J的日志冲突的问题
今天公司同事上线时发现,有的机器打印了日志,而有的机器则一条日志也没有打.以往都是没有问题的. 因此猜测是这次开发间接引入新的日志jar包,日志冲突导致未打印. 排查代码发现,系统使用的是SLF4J框 ...