C. Digit Tree

time limit per test:3 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output

ZS the Coder has a large tree. It can be represented as an undirected connected graph of n vertices numbered from 0 to n - 1 and n - 1edges between them. There is a single nonzero digit written on each edge.

One day, ZS the Coder was bored and decided to investigate some properties of the tree. He chose a positive integer M, which iscoprime to 10, i.e. .

ZS consider an ordered pair of distinct vertices (u, v) interesting when if he would follow the shortest path from vertex u to vertex v and write down all the digits he encounters on his path in the same order, he will get a decimal representaion of an integer divisible by M.

Formally, ZS consider an ordered pair of distinct vertices (u, v) interesting if the following states true:

  • Let a1 = u, a2, ..., ak = v be the sequence of vertices on the shortest path from u to v in the order of encountering them;
  • Let di (1 ≤ i < k) be the digit written on the edge between vertices ai and ai + 1;
  • The integer  is divisible by M.

Help ZS the Coder find the number of interesting pairs!

Input

The first line of the input contains two integers, n and M (2 ≤ n ≤ 100 000, 1 ≤ M ≤ 109, ) — the number of vertices and the number ZS has chosen respectively.

The next n - 1 lines contain three integers each. i-th of them contains ui, vi and wi, denoting an edge between vertices ui and vi with digit wi written on it (0 ≤ ui, vi < n,  1 ≤ wi ≤ 9).

Output

Print a single integer — the number of interesting (by ZS the Coder's consideration) pairs.

Examples

input
6 7
0 1 2
4 2 4
2 0 1
3 0 9
2 5 7
output
7
input
5 11
1 2 3
2 0 3
3 0 3
4 3 3
output
8

Note

In the first sample case, the interesting pairs are (0, 4), (1, 2), (1, 5), (3, 2), (2, 5), (5, 2), (3, 5). The numbers that are formed by these pairs are 14, 21, 217, 91, 7, 7, 917 respectively, which are all multiples of 7. Note that (2, 5) and (5, 2) are considered different.

In the second sample case, the interesting pairs are (4, 0), (0, 4), (3, 2), (2, 3), (0, 1), (1, 0), (4, 1), (1, 4), and 6 of these pairs give the number 33 while 2 of them give the number 3333, which are all multiples of 11.

Solution

一道比较好想好写的点分治

点分治显然,考虑如何计算复合的路径条数。

对于每个点我们维护两个值$Dig[x],Dig'[x]$,表示重心到这个点的路径组成的数,以及这个点到重心组成的数

这样对于一个点对$<u,v>$我们可以知道他们的$Dig[u],Dig[v],Dig'[u],Dig'[v]$,那么他们所组成的数就是$Dig'[u]*10^{k}+Dig[v]$

这个$k$我们发现,就相当于是$deep[u]$,知道这些就有思路搞了

题目的要求就是$Dig<u,v>mod M=0$也就可以转化成$Dig'[u]*10^{deep[u]}+Dig[v]\equiv 0(modM)$

然后整理一下就可以得到$Dig'[u]\equiv -Dig[v]*\frac{1}{10^{deep[u]}}$

然后用map存一下式子右边,对于一个点,它对答案的贡献就是hash表里的$Dig'[u]$的数量

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
#define LL long long
inline int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 100010
int N,M;
map<LL,LL>hash;
LL ans;
namespace Math
{
LL power[MAXN],Inv[MAXN];
inline LL Gcd(LL a,LL b) {if (!b) return a; else return Gcd(b,a%b);}
inline void ExGcd(LL a,LL b,LL &x,LL &y) {if (!b) {x=,y=; return;} ExGcd(b,a%b,y,x); y-=(a/b)*x;}
inline LL inv(LL X) {LL x,y; ExGcd(X,M,x,y); return (x%M+M)%M;}
inline LL Pow(LL x,LL y) {LL re=; for (LL i=y; i; i>>=,x=x*x%M) if (i&) re=re*x%M; return re;}
}
using namespace Math;
namespace TreeDivide
{
struct EdgeNode{int next,to,val;}edge[MAXN<<];
int head[MAXN],cnt=;
inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].to=v; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].val=w;}
inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
int size[MAXN],f[MAXN],visit[MAXN],root,deep[MAXN],Sz;
LL Dig[MAXN];
inline void Getroot(int x,int last)
{
size[x]=,f[x]=;
for (int i=head[x]; i; i=edge[i].next)
if (!visit[edge[i].to] && edge[i].to!=last)
{
Getroot(edge[i].to,x);
size[x]+=size[edge[i].to];
f[x]=max(f[x],size[edge[i].to]);
}
f[x]=max(f[x],Sz-f[x]);
if (f[x]<f[root]) root=x;
}
inline void DFS(int now,int last)
{
LL D=(((M-Dig[now])+M)%M*Inv[deep[now]])%M; hash[D]++;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
deep[edge[i].to]=deep[now]+,
Dig[edge[i].to]=(Dig[now]*%M+edge[i].val)%M,
DFS(edge[i].to,now);
}
inline LL Get(int now,int last)
{
LL re=hash[Dig[now]];
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last && !visit[edge[i].to])
Dig[edge[i].to]=(edge[i].val*power[deep[now]]%M+Dig[now])%M,
deep[edge[i].to]=deep[now]+,
re+=Get(edge[i].to,now);
return re;
}
inline void Divide(int now)
{
visit[now]=;
hash.clear(); hash[]--;
Dig[now]=0LL,deep[now]=;
DFS(now,);
ans+=Get(now,);
for (int i=head[now]; i; i=edge[i].next)
if (!visit[edge[i].to])
hash.clear(),hash[]--,
Dig[edge[i].to]=edge[i].val%M,deep[edge[i].to]=,
DFS(edge[i].to,now),
ans-=Get(edge[i].to,now);
for (int i=head[now]; i; i=edge[i].next)
if (!visit[edge[i].to])
Sz=size[edge[i].to],f[root=]=N,
Getroot(edge[i].to,now),Divide(root);
}
}
using namespace TreeDivide;
int main()
{
N=read(),M=read();
for (int x,y,z,i=; i<=N-; i++) x=read()+,y=read()+,z=read(),InsertEdge(x,y,z);
for (int i=; i<=N; i++) power[i]=Pow(,i),Inv[i]=inv(power[i]);
Sz=N; f[root=]=N+;
Getroot(,); Divide(root);
printf("%I64d\n",ans);
return ;
}

【Codeforces715C&716E】Digit Tree 数学 + 点分治的更多相关文章

  1. 【Codeforces 715C】Digit Tree(点分治)

    Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...

  2. CF 716E. Digit Tree [点分治]

    题意:一棵树,边上有一个个位数字,走一条路径会得到一个数字,求有多少路径得到的数字可以整除\(P\) 路径统计一般就是点分治了 \[ a*10^{deep} + b \ \equiv \pmod P\ ...

  3. 【题解】Digit Tree

    [题解]Digit Tree CodeForces - 716E 呵呵以为是数据结构题然后是淀粉质还行... 题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数. ...

  4. Codeforces 716 E Digit Tree

    E. Digit Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...

  5. hdu 4670 Cube number on a tree(点分治)

    Cube number on a tree Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/ ...

  6. 『sumdiv 数学推导 分治』

    sumdiv(POJ 1845) Description 给定两个自然数A和B,S为A^B的所有正整数约数和,编程输出S mod 9901的结果. Input Format 只有一行,两个用空格隔开的 ...

  7. 【POJ1741】Tree(点分治)

    [POJ1741]Tree(点分治) 题面 Vjudge 题目大意: 求树中距离小于\(K\)的点对的数量 题解 完全不觉得点分治了.. 简直\(GG\),更别说动态点分治了... 于是来复习一下. ...

  8. CF716E Digit Tree 点分治

    题意: 给出一个树,每条边上写了一个数字,给出一个P,求有多少条路径按顺序读出的数字可以被P整除.保证P与10互质. 分析: 统计满足限制的路径,我们首先就想到了点分治. 随后我们就需要考量,我们是否 ...

  9. [poj1741][tree] (树/点分治)

    Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Def ...

随机推荐

  1. CSS3-05 样式 4

    前言 关于 CSS 的介绍,基本上告一段落了.在该博客中将介绍如何通过 CSS 去设置一个 HTML 元素,显示在 Web 页面的位置. 定位 概述 定义元素位置的基准,即:该元素与 HTML 文档流 ...

  2. [css]我要用css画幅画(五)

    接着之前的[css]我要用css画幅画(四), 这次我给小明和静静增加了对话,用了简单的动画效果. github:https://github.com/bee0060/Css-Paint , 完整代码 ...

  3. 125个工具与技术(PMBOK2008)

    名称 定义 适用场景 适用过程 专家判断 对某方面擅长的人就是专家,找专家协助就是专家判断,专家可能是顾问.干系人.PMO.团队成员 制定项目章程.制定项目管理计划.指导与管理项目执行.监控项目工作. ...

  4. CLR垃圾回收的设计

    作者: Maoni Stephens (@maoni0) - 2015 附: 关于垃圾回收的信息,可以参照本文末尾资源章节里引用的垃圾回收手册一书. 组件架构 GC包含的两个组件分别是内存分配器和垃圾 ...

  5. ORACLE计算表引占用空间大小

    在ORACLE数据库中,如何计算一个表所占用的存储空间呢?我们可以通过系统视图DBA_SEGMENTS.USER_SEGMETNS.DBA_TABLES来查看一个表所占空间的大小,如下所示:   SE ...

  6. .net C# SqlHelper for Oracle

    适用于Oracle的sqlhelper 需要使用ODP.Net,引用Oracle.DataAccess.dll 推荐安装ODAC 代码如下: using System; using System.Co ...

  7. composer "Illegal offset type in isset or empty"报错解决方案

    最近更新了composer版本,即执行以下任一命令 composer selfupdate | composer self-update 再次执行 composer update -vvv 会出现“I ...

  8. 深入解析SQL Server并行执行原理及实践(下)

    谈完并行执行的原理,咱们再来谈谈优化,到底并行执行能给我们带来哪些好处,我们又应该注意什么呢,下面展开. Amdahl’s  Law 再谈并行优化前我想有必要谈谈阿姆达尔定律,可惜老爷子去年已经驾鹤先 ...

  9. linux 安装jdk

    1.Linux安装JDK步骤1. 先从网上下载jdk(jdk-1_5_0_02-linux-i586.rpm) ,推荐SUN的官方网站www.sun.com,下载后放在/home目录中,当然其它地方也 ...

  10. 萌新笔记——C++里将string类字符串(utf-8编码)分解成单个字(可中英混输)

    最近在建词典,使用Trie字典树,需要把字符串分解成单个字.由于传入的字符串中可能包含中文或者英文,它们的字节数并不相同.一开始天真地认为中文就是两个字节,于是很happy地直接判断当前位置的字符的A ...