AC通道:http://codeforces.com/problemset/problem/715/C
【题目大意】
给定一个有N个点的树,问其中有多少条路径满足他们的边权连成的数对M取余为0。
其中gcd(M,10)=1。
【题解】
首先是点分治的套路,然后这题的主要难点在如何统计连通块中的答案。
对于x→y的路径,也就是x→root→y,我们可以处理出dis[x]和dis[y]分别表示x到root、root到y连成的数对mod取模的结果
那么在合并时,如果路径合法,则应满足以下条件:
即:
然后我们就可以愉快地使用dfs统计答案了。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
#define FILE "read"
#define MAXN 1000010
#define INF 1000000000
#define up(i,j,n) for(ll i=j;i<=n;++i)
#define dn(i,j,n) for(ll i=j;i>=n;--i)
#define cmax(a,b) a=max(a,b)
#define cmin(a,b) a=min(a,b)
namespace INIT{
char buf[1<<15],*fs,*ft;
inline char getc(){return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
inline ll read(){
ll x=0,f=1; char ch=getc();
while(!isdigit(ch)) {if(ch=='-') f=-1; ch=getc();}
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getc();}
return x*f;
}
}using namespace INIT;
struct node{ll y,next,v;}e[MAXN*2];
ll n,mod,sum,root,len,ans,Link[MAXN],dis[MAXN],inv[MAXN],p[MAXN],deep[MAXN],size[MAXN],f[MAXN],vis[MAXN];
map<ll,ll>cnt;
void insert(ll x,ll y,ll v){e[++len].next=Link[x];Link[x]=len;e[len].y=y;e[len].v=v;}
void exgcd(ll a,ll b,ll &x,ll &y){
if(!b) {x=1;y=0;return;}
exgcd(b,a%b,x,y);
ll t=x;x=y;y=t-a/b*y;
}
ll Ni(ll num){
ll x,y; exgcd(num,mod,x,y);
return (x%mod+mod)%mod;
}
void pre(){
p[0]=1;up(i,1,n)p[i]=p[i-1]*10%mod;
up(i,0,n)inv[i]=Ni(p[i]);
}
void getroot(ll x,ll fa){
f[x]=0; size[x]=1;
for(ll i=Link[x];i;i=e[i].next){
if(e[i].y==fa||vis[e[i].y]) continue;
getroot(e[i].y,x); size[x]+=size[e[i].y];
cmax(f[x],size[e[i].y]);
}
cmax(f[x],sum-size[x]);
if(f[x]<f[root]) root=x;
}
void dfs(ll x,ll fa){
ll temp=((mod-dis[x]*inv[deep[x]])%mod+mod)%mod; cnt[temp]++;
for(ll i=Link[x];i;i=e[i].next){
if(vis[e[i].y]||e[i].y==fa) continue;
dis[e[i].y]=(dis[x]*10%mod+e[i].v)%mod;
deep[e[i].y]=deep[x]+1;
dfs(e[i].y,x);
}
}
ll get(ll x,ll fa){
ll temp=cnt[dis[x]%mod];
for(ll i=Link[x];i;i=e[i].next){
if(vis[e[i].y]||e[i].y==fa) continue;
deep[e[i].y]=deep[x]+1;
dis[e[i].y]=(dis[x]+e[i].v*p[deep[x]]%mod)%mod;
temp+=get(e[i].y,x);
}
return temp;
}
ll cal(ll x,ll v,ll depth){
dis[x]=v%mod; deep[x]=depth;
dfs(x,0); cnt[0]--;
return get(x,0);
}
void solve(ll x){
vis[x]=1; cnt.clear(); ans+=cal(x,0,0);
for(ll i=Link[x];i;i=e[i].next){
if(vis[e[i].y]) continue;
cnt.clear();
ans-=cal(e[i].y,e[i].v,1);
root=0; sum=size[e[i].y]; getroot(e[i].y,0);
solve(root);
}
}
int main(){
freopen(FILE".in","r",stdin);
freopen(FILE".out","w",stdout);
n=sum=read(); mod=read(); f[0]=INF; pre();
up(i,1,n-1){ll x=read()+1,y=read()+1,v=read()%mod;insert(x,y,v);insert(y,x,v);}
getroot(1,0); solve(root);
printf("%lld\n",ans);
return 0;
}