分析:
说实话,并不知道这题怎么用启发式合并来做。。。总之它就放在启发式合并的练习里面了。。。但我就是用点分治做的。。。
其实这题点分治做起来非常简单。。。
首先先向下找每条到达当前重心的路径的权值,将其设为
然后再每条边依次考虑从重心走下去的权值,将其设为
然后对于这个重心的方案无非就是 的方案数( 这个链的长度)。
然后稍微转化一下,变成
。
所以预处理一下
的方案数,然后再暴力找
这一侧就可以了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#include<map>
#define SF scanf
#define PF printf
#define MAXN 100010
using namespace std;
typedef long long ll;
int dp[MAXN];
vector<int>hv[2];
vector<int> a[MAXN];
vector<ll> w[MAXN];
bool vis[MAXN];
int now;
void dfs(int x,int fa){
dp[x]=1;
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(u==fa||vis[u])
continue;
dfs(u,x);
dp[x]+=dp[u];
}
}
int dfs1(int x,int fa,int siz){
int minid=-1;
dp[x]=siz-dp[x];
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(u==fa||vis[u])
continue;
dp[x]=max(dp[x],dp[u]);
int v=dfs1(u,x,siz);
if(minid==-1||dp[v]<dp[minid])
minid=v;
}
if(minid==-1||dp[x]<dp[minid])
minid=x;
return minid;
}
int get_hv(int x){
dfs(x,0);
return dfs1(x,0,dp[x]);
}
int n;
ll ans,p;
map<ll,int> used;
ll fsp[MAXN],ifsp[MAXN];
void dfs2(int x,int fa,ll pre,int dep){
ans+=used[(p-pre)*ifsp[dep]%p];
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(vis[u]==1||u==fa)
continue;
dfs2(u,x,(pre*10ll+w[x][i])%p,dep+1);
}
}
void dfs3(int x,int fa,ll pre,int dep,int val){
used[pre]+=val;
for(int i=0;i<a[x].size();i++){
int u=a[x][i];
if(vis[u]==1||u==fa)
continue;
dfs3(u,x,(pre+fsp[dep]*w[x][i])%p,dep+1,val);
}
}
void solve(int x){
used.clear();
used[0]++;
for(int i=0;i<a[x].size();i++){
if(vis[a[x][i]])
continue;
dfs3(a[x][i],x,w[x][i],1,1);
}
for(int i=0;i<a[x].size();i++){
if(vis[a[x][i]])
continue;
dfs3(a[x][i],x,w[x][i],1,-1);
dfs2(a[x][i],x,w[x][i],1);
dfs3(a[x][i],x,w[x][i],1,1);
}
ans+=(used[0]-1);
}
void work(){
while(hv[now].size()){
for(int i=0;i<hv[now].size();i++){
int x=hv[now][i];
solve(x);
vis[x]=1;
for(int i=0;i<a[x].size();i++)
if(vis[a[x][i]]==0)
hv[now^1].push_back(get_hv(a[x][i]));
}
hv[now].clear();
now^=1;
}
}
void exgcd(ll a,ll b,ll &x,ll &y){
if(b==0){
x=1;
y=0;
return;
}
exgcd(b,a%b,x,y);
ll xx=y;
ll yy=x-a/b*y;
x=xx;
y=yy;
}
ll get_inv(ll x,ll y){
ll xx,yy;
exgcd(x,y,xx,yy);
return (xx%y+y)%y;
}
int main(){
SF("%d%d",&n,&p);
fsp[0]=1;
for(int i=1;i<=n;i++)
fsp[i]=fsp[i-1]*10ll%p;
ifsp[n]=get_inv(fsp[n],p);
for(int i=n;i>=1;i--)
ifsp[i-1]=ifsp[i]*10ll%p;
int u,v,val;
for(int i=1;i<n;i++){
SF("%d%d%d",&u,&v,&val);
val%=p;
a[u].push_back(v);
a[v].push_back(u);
w[u].push_back(val);
w[v].push_back(val);
}
hv[0].push_back(get_hv(0));
work();
PF("%I64d",ans);
}