zoukankan      html  css  js  c++  java
  • CF716E Digit Tree 点分治

    题意:

      给出一个树,每条边上写了一个数字,给出一个P,求有多少条路径按顺序读出的数字可以被P整除。保证P与10互质。

    分析:

      统计满足限制的路径,我们首先就想到了点分治。

      随后我们就需要考量,我们是否能统计过某个点的合法路径。我们看,由题目性质,我们可以求对于一个根,所有点到根的路径组成的数,以及根到所有点的路径所组成的数。然后我们就可以对前者开一个数组(其实是一个map容器),后者在上面查询,然后用点分治的去重套路,保证答案不重不漏。

    代码:

     1 #include<bits/stdc++.h>
     2 #define int long long
     3 using namespace std;
     4 const int N=100005,inf=0x3f3f3f3f;
     5 struct node{int y,z,nxt;}e[N*2];int ans;
     6 int sm,h[N],c=1,vis[N],d[N],siz[N],mx[N];
     7 int rt,n,m,pw[N],tot,dis[N];map<int,int>mp;
     8 void add(int x,int y,int z){
     9     e[++c]=(node){y,z,h[x]};h[x]=c;
    10     e[++c]=(node){x,z,h[y]};h[y]=c;
    11 } void getrt(int x,int fa){
    12     siz[x]=1;mx[x]=0;
    13     for(int i=h[x],y;i;i=e[i].nxt)
    14     if((y=e[i].y)!=fa&&!vis[y]){
    15         getrt(y,x);siz[x]+=siz[y];
    16         mx[x]=max(mx[x],siz[y]);
    17     } mx[x]=max(mx[x],sm-siz[x]);
    18     if(mx[x]<mx[rt]) rt=x;return ;
    19 } void exgcd(int a,int b,int &d,int &x,int &y){
    20     if(!b) d=a,x=1,y=0;
    21     else exgcd(b,a%b,d,y,x),y-=x*(a/b);
    22 } int inv(int a,int p){
    23     int x,y,d;exgcd(a,p,d,x,y);
    24     return d==1?(x%p+p)%p:-1;
    25 } void dfs(int x,int fa,int v1,int v2,int dep){
    26     if(dep){
    27         mp[v2%m]++;dis[++tot]=v1;d[tot]=dep;
    28     } for(int i=h[x],y;i;i=e[i].nxt)
    29     if((y=e[i].y)!=fa&&!vis[y]){
    30         dfs(y,x,(v1*10%m+e[i].z)%m,
    31         (v2+e[i].z*pw[dep]%m)%m,dep+1);
    32     } return ;
    33 } int calc(int x,int v,int op){
    34     int res=0;tot=0;mp.clear();
    35     dfs(x,0,v,v,op);
    36     for(int i=1;i<=tot;i++){
    37         int val=(m-dis[i]*inv(pw[d[i]],m)%m)%m;
    38         if(mp.find(val)!=mp.end()) res+=mp[val];
    39         if(!op) res+=(dis[i]==0);
    40     } if(!op) res+=mp[0];return res;
    41 } void solve(int x){
    42     ans+=calc(x,0,0);vis[x]=1;
    43     for(int i=h[x],y;i;i=e[i].nxt)
    44     if(!vis[y=e[i].y]){
    45         ans-=calc(y,e[i].z,1);
    46         mx[rt=0]=inf;sm=siz[y];
    47         getrt(y,0);solve(rt);
    48     } return ;
    49 } signed main(){
    50     scanf("%lld%lld",&n,&m);
    51     for(int i=1,x,y,z;i<n;i++)
    52     scanf("%lld%lld%lld",&x,&y,&z),
    53     add(x+1,y+1,z);
    54     pw[0]=1;for(int i=1;i<=n;i++)
    55     pw[i]=1ll*pw[i-1]*10%m;
    56     mx[rt=0]=inf;sm=n;
    57     getrt(1,0);solve(rt);
    58     printf("%lld
    ",ans);
    59     return 0;
    60 }
    点分治
  • 相关阅读:
    《Linux设备驱动开发详解(第3版)》(即《Linux设备驱动开发详解:基于最新的Linux 4.0内核》)--宋宝华
    WebApp 安全风险与防护课堂开课了!
    2019 Vue开发指南:你都需要学点啥?
    每个程序员都该学习的5种开发语言
    每个Web开发者都该了解的12条命令行
    Webpack 4教程
    都 9012了,该选择 Angular、React,还是Vue?
    在 Angular 8 中,我们可以期待些什么
    “宇宙最强” IDE,Visual Studio 2019 正式发布
    Webpack 4教程
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10429708.html
Copyright © 2011-2022 走看看