【题解】Digit Tree

【题解】Digit Tree

CodeForces - 716E

呵呵以为是数据结构题然后是淀粉质还行...

题目就是给你一颗有边权的树,问你有多少路径,把路径上的数字顺次写出来,是\(m\)的倍数。

很明显可以点分治嘛,我们可以按照图上的样子,把一条路径本来是\(12345678\)的路径,变成\(1234|5678\),我们记录图中左边的那种路径为\(f\)(往根),右边的那种路径为\(g\)(从根),记右边的那种到分治中心的深度为\(d\),那么这条路径就可以被表示成\(f\times 10^d+g\),条件就变成了
\[
f \times 10^d +g\equiv 0
\f \times 10^d \equiv -g
\f \equiv -g \times 10^{-d}
\]
我们把坐边压到一个\(map\)里面,每次分治时拿右边直接枚举就好了,然后还要用第二个\(map\)去掉同一颗子树内的非法情况,具体实现看代码。

由于处理这个\(f,g\)真的很难(博主搞了好久,自己都晕了),所以代码里的\(f,g\)可能是反的...

不觉得难的可以自己去试试,如果你真的没晕的话..收下我的膝盖orz

咱们把\(map\)看做一个\(log\),时间复杂度就是\(O(n \log^2n)\)的

#include<bits/stdc++.h>
using namespace std;  typedef long long ll;
template < class ccf > inline ccf qr(ccf ret){      ret=0;
      register char c=getchar();
      while(not isdigit(c)) c=getchar();
      while(isdigit(c)) ret=ret*10+c-48,c=getchar();
      return ret;
}
const int maxn=1e5+5;
typedef pair < int , ll > P;
vector < P > e[maxn];
vector < int > ve;
#define pb push_back
#define st first
#define nd second
#define mk make_pair
inline void add(int fr,int to,int w){
      e[fr].pb(mk(to,w));
      e[to].pb(mk(fr,w));
}
int sum;
int siz[maxn];
int d0[maxn];//深度
int f[maxn];
int g[maxn];
int rt;
int spc[maxn];
int inv[maxn];
int ten[maxn];
bool usd[maxn];
int n,mod;
map < int , int > mp,un;
ll ans;

void dfsrt(const int&now){//重心
      usd[now]=1;
      siz[now]=spc[now]=1;
      for(auto t:e[now])
            if(not usd[t.first]){
                  dfsrt(t.st);
                  siz[now]+=siz[t.st];
                  if(siz[t.st]>spc[now])spc[now]=siz[t.st];
            }
      spc[now]=max(spc[now],sum-siz[now]);
      if(spc[now]<spc[rt]|| not rt) rt=now;
      usd[now]=0;
}

void dfsd(const int&now,const int& last,const int&w){//dis
      usd[now]=1;
      d0[now]=d0[last]+1;
      g[now]=(g[last]+1ll*ten[d0[last]]*w%mod)%mod;
      f[now]=(f[last]*10ll%mod+w)%mod;
      //printf("now=%d d0=%d f=%d g=%d\n",now-1,d0[now],f[now],g[now]);
      ans+=(f[now]==0)+(g[now]==0);
      ++un[g[now]];
      ++mp[g[now]];
      ve.pb(now);
      for(auto t:e[now])
            if(not usd[t.st])
                  dfsd(t.st,now,t.nd);
      usd[now]=0;
}

inline void calc(const int&now){
      d0[now]=f[now]=g[now]=0;
      ve.clear();mp.clear();
      int k=0;
      for(auto t:e[now])
            if(not usd[t.st]){
                  un.clear();
                  dfsd(t.st,now,t.nd);
                  register int edd=ve.size();
                  while(k<edd){
                        register int it=ve[k];
                        register int p=1ll*(((mod-f[it])%mod+mod)%mod)*inv[d0[it]]%mod;
                        if(un.find(p)!=un.end())
                              ans-=un[p];
                        ++k;
                  }
            }
      for(auto t:ve){
            register int p=1ll*(((mod-f[t])%mod+mod)%mod)*inv[d0[t]]%mod;
            if(mp.find(p)!=mp.end())
                  /*cout<<"?qaq="<<t-1<<' '<<p<<endl;*/
                  ans+=mp[p];
      }

}

void divd(const int&now){
      usd[now]=1;calc(now);
      for(auto t:e[now])
            if(not usd[t.st]){
                  sum=siz[t.st];rt=0;
                  dfsrt(t.st);
                  divd(rt);
            }
}

void exgcd(int a,int b,int&d,int&x,int&y){
      if(!b) d=a,x=1,y=0;
      else exgcd(b,a%b,d,y,x),y-=x*(a/b);
}

int Inv(const int&a, const int&p){
      int d,x,y;
      exgcd(a,p,d,x,y);
      return d==1?(x+p)%p:-1;
}

int main(){
      sum=n=qr(1);mod=qr(1);
      if(mod==1)return cout<<1ll*n*(n-1)<<endl,0;
      inv[0]=ten[0]=1;
      ten[1]=10;
      inv[1]=Inv(10,mod);
      if(inv[1]==-1)return -1;
      for(register int t=2;t<=n+1;++t)
            ten[t]=1ll*ten[t-1]*ten[1]%mod,inv[t]=1ll*inv[t-1]*inv[1]%mod;
      for(register int t=1,t1,t2,t3;t< n;++t){
            t1=qr(1)+1;t2=qr(1)+1;t3=qr(1);
            add(t1,t2,t3);
      }
      dfsrt(1);
      divd(rt);
      cout<<ans<<endl;
      return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/10651673.html

时间: 2024-10-01 12:53:10

【题解】Digit Tree的相关文章

[LeetCode 题解]: Binary Tree Preorder Traversal

Given a binary tree, return the preorder traversal of its nodes' values. For example:Given binary tree {1,#,2,3}, 1 2 / 3 return [1,2,3]. Note: Recursive solution is trivial, could you do it iteratively? 题意 先序遍历二叉树,递归的思路是普通的,能否用迭代呢? 非递归思路:<借助stack>

[LeetCode 题解]: Symmetric Tree

Given a binary tree, check whether it is a mirror of itself (ie, symmetric around its center). For example, this binary tree is symmetric: 1 / 2 2 / \ / 3 4 4 3 But the following is not: 1 / 2 2 \ 3 3 Note:Bonus points if you could solve it both recu

leetcode题解:Binary Tree Postorder Traversal (二叉树的后序遍历)

题目: Given a binary tree, return the postorder traversal of its nodes' values. For example:Given binary tree {1,#,2,3}, 1 2 / 3 return [3,2,1]. Note: Recursive solution is trivial, could you do it iteratively? 说明: 1) 两种实现,递归与非递归 , 其中非递归有两种方法 2)复杂度分析:时

leetcode题解:Tree Level Order Traversal II (二叉树的层序遍历 2)

题目: Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left to right, level by level from leaf to root). For example:Given binary tree {3,9,20,#,#,15,7}, 3 / 9 20 / 15 7 return its bottom-up level order tr

leetcode 题解:Binary Tree Level Order Traversal (二叉树的层序遍历)

题目: Given a binary tree, return the level order traversal of its nodes' values. (ie, from left to right, level by level). For example:Given binary tree {3,9,20,#,#,15,7}, 3 / 9 20 / 15 7 return its level order traversal as: [ [3], [9,20], [15,7] ] co

竞赛题解 - Broken Tree(CF-758E)

Broken Tree(CF-758E) - 竞赛题解 贪心复习~(好像暴露了什么算法--) 标签:贪心 / DFS 『题意』 给出一棵以1为根的树,每条边有两个值:p-强度.w-重量. 对于给出的树,我们可以对每条边进行操作--将它的p.w同时减去相同的值,但是要求 \(p\ge0,w>0\) .(注意只能减,不能加) 进行操作后,需要使原树满足:如果 u 是 v 的父亲,那么 u 到 v 的边的 p 不能小于 以 v 为根节点的子树中所有边的 w 之和. 求出一种方案,使得在满足条件的情况下

LeetCode(100)题解--Same Tree

https://leetcode.com/problems/same-tree/ 题目: Given two binary trees, write a function to check if they are equal or not. Two binary trees are considered equal if they are structurally identical and the nodes have the same value. 思路:  DFS AC代码: 1.递归 1

CF715C:Digit Tree

传送门 一句话怎么说来着 算法+高级数据结构=OI 现在我感觉到的是 我会的算法+我会的高级数据结构=WA 这道题提交了三四十次,从刚看题到完全写好花了好几天..,主要死于看错费马小定理的适用条件. 下面是正经题解: 首先,这道题的难点不在于找到有多少个路径(很明显的点分治),而是判断一条路径是否合法. 按照点分治的一般套路.我们可以求出从一个点出发的所有路径,然而把所有路径组合起来就好了. 显然,对于把从$root$到所有子节点的路径的那个数只要不断的乘上去然后$modM$就行了. 所有我们面

[Codeforces 715C] Digit Tree

[题目链接] https://codeforces.com/contest/715/problem/C [算法] 考虑点分治 一条路径(x , y)合法当且仅当 : d(x) * 10 ^ dep(x) + d(y) = 0(mod m) , 其中d(u)表示u到分治重心路径上数字拼接起来所形成的数 统计答案时 , 我们只需维护一个map , 维护10 ^ -dep(u) * d(u) (mod m) 然后计算每个点的贡献即可 时间复杂度 : O(NlogN ^ 2) [代码] #include