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< ...
随机推荐
- JVM:内存模型
JVM:内存模型 说明:这是看了 bilibili 上 黑马程序员 的课程 JVM完整教程 后做的笔记 1. java 内存模型 很多人将[java 内存结构]与[java 内存模型]傻傻分不清,[j ...
- 扩展spring data jpa的repository
在我们编写代码的过程中,spring data jpa为我们的持久层提供的极大的方便,但有时spring data jpa提供的repository并不能完全满足我们开发的需求,因此就需要进行扩展.s ...
- SCons - 简单而强大的项目编译脚本(原文https://www.cnblogs.com/binchen-china/p/5646791.html)
N年前学的makefile,当时还勉强能写一些简单的工程编译,现在已经基本忘了.makefile确实编写复杂,而且平时也不是经常使用,容易忘记.偶识了scons,一切都变的简单了.最近研究了下scon ...
- HDI PCB一阶和二阶和三阶如何区分??
一阶板,一次压合即成,可以想像成最普通的板二阶板,两次压合,以盲埋孔的八层板为例,先做2-7层的板,压好,这时候2-7的通孔埋孔已经做好了,再加1层和8层压上去,打1-8的通孔,做成整板.三阶板就 ...
- ssh key公钥
在ubuntu上生成ssh key 首先使用 ls -al ~/.ssh 查看本地是否已经有key 如果没有会显示如下: ~$ ls -al ~/.ssh ls: cannot access '/ho ...
- Java RMI学习与解读(三)
Java RMI学习与解读(三) 写在前面 接下来这篇就是最感兴趣的Attack RMI部分了. 前面也说过,RMI的通信过程会用到反序列化,那么针对于RMI的三个角色: Server/Regisrt ...
- C语言图书管理借阅系统——ncurses库的使用
一.前言 作为一只大四狗,最近还跟着大二同学修了一门课(当然不是之前没通过啦),课程是高级语言课程设计,高级语言指的是C语言 :),内容是做一个XX管理系统,我选择了图书管理系统,先介绍下我做的系统: ...
- 攻防世界 Misc 新手练习区 stegano CONFidence-DS-CTF-Teaser Writeup
攻防世界 Misc 新手练习区 stegano CONFidence-DS-CTF-Teaser Writeup 题目介绍 题目考点 隐写术 摩斯密码 Writeup 下载附件是PDF文件打开,研究一 ...
- PTA 7-1 公路村村通 (30分)
PTA 7-1 公路村村通 (30分) 现有村落间道路的统计数据表中,列出了有可能建设成标准公路的若干条道路的成本,求使每个村落都有公路连通所需要的最低成本. 输入格式: 输入数据包括城镇数目正整数N ...
- 暑假算法练习Day2
第二天啦!大家一起冲冲冲!! 1004 成绩排名 (20 分) 读入 n(>0)名学生的姓名.学号.成绩,分别输出成绩最高和成绩最低学生的姓名和学号. 输入格式: 每个测试输入包含 1 个测试用 ...