CF715C Digit Tree
统计路径数量,考虑点分治试试。那么问题就转化为对于每一个点 \(u\),给定四个点集,第一组与第二组考虑贡献,第三组与第四组考虑贡献。考虑 \(A,B\) 集合之间的贡献即计数二元组 \((a,b) a \in A,b \in B\) 满足 \(d_a + D_b \times 10^{\text{dis}(u,a)} \equiv 0 \pmod {m}\),也就是 \(d_a \times (10^{\text{dis}(u,a)})^{-1} \equiv D_b \pmod {m}\)。注意正反都要考虑,这也是有四个点集的原因。
#include <bits/stdc++.h>
using namespace std;
#define typ int
inline char gc(){static char buf[100000] , *p1 = buf , *p2 = buf;return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;}inline typ read(){typ x = 0; bool f = 0;char ch = gc();while(!isdigit(ch)){f |= (ch == '-');ch = gc();}while(isdigit(ch)){x = (x << 1) + (x << 3) + (ch ^ 48);ch = gc();}return (f ? -x : x);}
const int N = 1e5 + 5;
int n , m;
inline int Add(int x , int y){return x + y < m ? x + y : x + y - m;}
inline int Sub(int x , int y){return x < y ? x + m - y : x - y;}
inline int Mul(int x , int y){return 1LL * x * y % m;}
int pw10[N] , ip10[N];
using uii = unordered_map<int,int>;
using vii = vector<pair<int,int> >;
vii E[N] , buc;
uii mp1 , mp2;
int siz[N] , sum , rt , mk[N];
pair<int,int> dis[N];
signed main(){
function<void(int,int,int&,int&)> exgcd = [&] (int a , int b , int &x , int &y) -> void {
if(b == 0) return (void)(x = 1 , y = 0);
int X , Y;
exgcd(b , a % b , X , Y);
x = Y;
y = X - (a / b) * Y;
};
n = read() , m = read();
for(int i = 1; i < n; ++ i){
int u = read() + 1 , v = read() + 1 , w = read() % m;
E[u].push_back({v , w});
E[v].push_back({u , w});
}
pw10[0] = 1; ip10[0] = 1;
int temp;
if(m > 10) exgcd(m , 10 , temp , ip10[1]);
if(m < 10) exgcd(10 , m , ip10[1] , temp);
ip10[1] = Sub(ip10[1] , 0);
for(int i = 1; i <= n; ++ i){
pw10[i] = Mul(pw10[i - 1] , 10);
ip10[i] = Mul(ip10[i - 1] , ip10[1]);
}
function<void(int,int)> getrt = [&] (int u , int fa) -> void {
siz[u] = 1;
int maxs = 0;
for(auto [v , w] : E[u]){
if(v == fa || mk[v]) continue;
getrt(v , u);
siz[u] += siz[v];
maxs = max(maxs , siz[v]);
}
maxs = max(maxs , sum - siz[u]);
if(maxs <= sum / 2) rt = u;
};
function<void(int,int,int)> getdis = [&] (int u , int fa , int stp) -> void {
auto [x , y] = dis[u];
x = Mul(x , ip10[stp]);
buc.push_back({x , y});
for(auto [v , w] : E[u]){
if(v == fa || mk[v]) continue;
auto [x , y] = dis[u];
dis[v] = {Add(Mul(x , 10) , w) , Add(Mul(pw10[stp] , w) , y)};
getdis(v , u , stp + 1);
}
};
long long ans = 0;
auto calc = [&] (int u) -> void {
uii ().swap(mp1);
uii ().swap(mp2);
mp1[0] = mp2[0] = 1;
for(auto [v , w] : E[u]){
if(mk[v]) continue;
vii ().swap(buc);
dis[v] = {w , w};
getdis(v , u , 1);
for(auto [d , D] : buc){
int tmp1 = m - d , tmp2 = m - D;
if(tmp1 == m) tmp1 = 0;
if(tmp2 == m) tmp2 = 0;
if(mp1.find(tmp1) != mp1.end()){
ans += mp1[tmp1];
}
if(mp2.find(tmp2) != mp2.end()){
ans += mp2[tmp2];
}
}
for(auto [d , D] : buc) mp1[D] ++ , mp2[d] ++ ;
}
};
function<void(int)> work = [&] (int u) -> void {
mk[u] = 1;
calc(u);
for(auto [v , w] : E[u]){
if(mk[v]) continue;
getrt(v , u);
sum = siz[v];
getrt(v , u);
work(rt);
}
};
sum = n;
getrt(1 , 0);
work(rt);
printf("%lld" , ans);
return 0;
}