CF715C:Digit Tree

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF715C:Digit Tree相关的知识,希望对你有一定的参考价值。

传送门

一句话怎么说来着

算法+高级数据结构=OI

现在我感觉到的是

我会的算法+我会的高级数据结构=WA

 

这道题提交了三四十次,从刚看题到完全写好花了好几天..,主要死于看错费马小定理的适用条件。

 

下面是正经题解:

首先,这道题的难点不在于找到有多少个路径(很明显的点分治),而是判断一条路径是否合法。

按照点分治的一般套路。我们可以求出从一个点出发的所有路径,然而把所有路径组合起来就好了。

显然,对于把从$root$到所有子节点的路径的那个数只要不断的乘上去然后$modM$就行了。

 

所有我们面临的最主要的问题就是如何把两条路径组合起来。

首先,这里指的路径并不是两条完全相同的路径。比如说我们要验证从$node_i$经$root$到$node_j$的路径,我们应该求出$node_i \\rightarrow root$数和$root \\rightarrow node_j$的数。

不妨设这两个数的为别为$num_i$和$num_j$,把他们的长度(或者说是从根到$node$的深度)即为$deep_i$和$deep_j$,显然,如果$node_i \\rightarrow node_j$的路径是合法的,我们可以得到以下关系。

$num_i+num_j \\times 10^{deep_j} \\equiv 0 (mod M)$

转换一下

 

$num_i \\equiv -num_j \\times 10^{-deep_j} (mod M)$

 

对于这个式子右边的,dfs一遍后用map存储即可。然后累加式子左边的即可。同时,要注意从统计式子右边完后,要-1,具体为什么实现的时候自己就能明白。

 

同时,$M$不一定为素数,所以这个模的意义一定要用乘法逆元或者欧拉函数什么的求,直接快速幂$M-2$会有问题。

 

技术分享
  1 //CF 716E
  2 //by Cydiater
  3 //2016.9.27
  4 #include <iostream>
  5 #include <cstring>
  6 #include <string>
  7 #include <algorithm>
  8 #include <queue>
  9 #include <map>
 10 #include <ctime>
 11 #include <cmath>
 12 #include <string>
 13 #include <cstdio>
 14 #include <cstdlib>
 15 #include <iomanip>
 16 using namespace std;
 17 #define ll long long
 18 #define up(i,j,n)        for(int i=j;i<=n;i++)
 19 #define down(i,j,n)        for(int i=j;i>=n;i--)
 20 const int MAXN=1e6+5;
 21 const int oo=0x3f3f3f3f;
 22 inline ll read(){
 23     char ch=getchar();ll x=0,f=1;
 24     while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();}
 25     while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
 26     return x*f;
 27 }
 28 map<ll,ll>cnt;
 29 ll N,mod,LINK[MAXN],len=0,pow10[MAXN],inv10[MAXN],root,sum,siz[MAXN],max_siz[MAXN],ans=0,dis[MAXN],deep[MAXN];
 30 struct edge{
 31     ll y,next,v;
 32 }e[MAXN];
 33 bool vis[MAXN];
 34 namespace solution{
 35     inline void insert(ll x,ll y,ll v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
 36     inline ll quick_pow(ll a,ll b){
 37         ll tmp=1;
 38         while(b){
 39             if(b&1)tmp=(tmp*a)%mod;
 40             b>>=1;a=(a*a)%mod;
 41         }
 42         return tmp;
 43     }
 44     void make_root(int node,int fa){
 45         siz[node]=1;max_siz[node]=0;
 46         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 47             make_root(e[i].y,node);
 48             siz[node]+=siz[e[i].y];
 49             max_siz[node]=max(max_siz[node],siz[e[i].y]);
 50         }
 51         max_siz[node]=max(max_siz[node],sum-max_siz[node]);
 52         if(max_siz[node]<max_siz[root])root=node;
 53     }
 54     void ex_gcd(ll a,ll b,ll &x,ll &y){
 55         if(b==0){x=1;y=0;return;}
 56         ex_gcd(b,a%b,x,y);
 57         ll t=x;x=y;y=t-a/b*y;
 58     }
 59     ll get_inv(ll num){
 60         ll x,y;
 61         ex_gcd(num,mod,x,y);
 62         return ((x%mod+mod)+mod)%mod;
 63     }
 64     void init(){
 65         N=read();mod=read();
 66         up(i,2,N){
 67             ll x=read()+1,y=read()+1,v=read(); 
 68             insert(x,y,v);
 69             insert(y,x,v);
 70         }
 71         if(mod<=1){
 72             cout<<N*(N-1)<<endl;
 73             exit(0);
 74         }
 75         pow10[0]=1;
 76         up(i,1,N)pow10[i]=(pow10[i-1]*10)%mod;
 77         up(i,0,N)inv10[i]=get_inv(pow10[i]);//pret
 78     }
 79     void dfs(ll node,ll fa){
 80         ll tmp=(((mod-dis[node])%mod+mod)*inv10[deep[node]]+mod)%mod;
 81         cnt[tmp]++;
 82         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 83             dis[e[i].y]=((dis[node]*10)%mod+e[i].v)%mod;
 84             deep[e[i].y]=deep[node]+1;
 85             dfs(e[i].y,node);
 86         }
 87     }
 88     ll get_ans(int node,int fa){
 89         ll tmp=cnt[dis[node]%mod];
 90         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]&&e[i].y!=fa){
 91             deep[e[i].y]=deep[node]+1;
 92             dis[e[i].y]=(dis[node]+(e[i].v*pow10[deep[node]])%mod)%mod;
 93             tmp+=get_ans(e[i].y,node);
 94         }
 95         return tmp;
 96     }
 97     ll col(int node,ll dist,int dep){
 98         dis[node]=dist%mod;deep[node]=dep;
 99         dfs(node,0);
100         cnt[0]--;
101         return get_ans(node,0);
102     }
103     void work(int node){
104         vis[node]=1;
105         cnt.clear();
106         ans+=col(node,0,0);
107         for(int i=LINK[node];i;i=e[i].next)if(!vis[e[i].y]){
108             cnt.clear();
109             ans-=col(e[i].y,e[i].v,1);
110             root=0;sum=siz[e[i].y];
111             make_root(e[i].y,0);
112             work(root);
113         }
114     }
115     void slove(){
116         root=0;max_siz[root]=oo;sum=N;
117         make_root(1,0);
118         work(root);
119     }
120     void output(){
121         cout<<ans<<endl;
122     }
123 }
124 int main(){
125     //freopen("input.in","r",stdin);
126     using namespace solution;
127     init();
128     slove();
129     output();
130 }
131     
View Code

 

以上是关于CF715C:Digit Tree的主要内容,如果未能解决你的问题,请参考以下文章

CF570D:Tree Requests

CF 570 D. Tree Requests

「CF911F」Tree Destruction

题解 CF375D Tree and Queries

CF 600E. Lomsat gelral(dsu on tree)

题解 CF375D Tree and Queries