【题解】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;
}

【题解】Digit Tree的更多相关文章

  1. 【Codeforces715C&716E】Digit Tree 数学 + 点分治

    C. Digit Tree time limit per test:3 seconds memory limit per test:256 megabytes input:standard input ...

  2. Codeforces 716 E Digit Tree

    E. Digit Tree time limit per test 3 seconds memory limit per test 256 megabytes input standard input ...

  3. 【Codeforces 715C】Digit Tree(点分治)

    Description 程序员 ZS 有一棵树,它可以表示为 \(n\) 个顶点的无向连通图,顶点编号从 \(0\) 到 \(n-1\),它们之间有 \(n-1\) 条边.每条边上都有一个非零的数字. ...

  4. [LeetCode 题解]: Binary Tree Preorder Traversal

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述 Given a bi ...

  5. [LeetCode 题解]: Symmetric Tree

    前言   [LeetCode 题解]系列传送门:  http://www.cnblogs.com/double-win/category/573499.html   1.题目描述   Given a ...

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

    Broken Tree(CF-758E) - 竞赛题解 贪心复习~(好像暴露了什么算法--) 标签:贪心 / DFS / Codeforces 『题意』 给出一棵以1为根的树,每条边有两个值:p-强度 ...

  7. [题解] 树(tree)

    题目大意 ​ 给定一颗 \(N\) 个点的有根树,其中 \(1\) 是树根,除了 \(1\) 以外的其他点 \(u\) 有唯一的父亲 \(Father_u\).同时,给定 \(M\) 条路径,第 \( ...

  8. CF715C:Digit Tree

    传送门 一句话怎么说来着 算法+高级数据结构=OI 现在我感觉到的是 我会的算法+我会的高级数据结构=WA 这道题提交了三四十次,从刚看题到完全写好花了好几天..,主要死于看错费马小定理的适用条件. ...

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

    题目: Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from ...

随机推荐

  1. 【MyBatis学习11】MyBatis中的延迟加载

    1. 什么是延迟加载 举个例子:如果查询订单并且关联查询用户信息.如果先查询订单信息即可满足要求,当我们需要查询用户信息时再查询用户信息.把对用户信息的按需去查询就是延迟加载. 所以延迟加载即先从单表 ...

  2. Nginx开发从入门到精通 nginx平台初探

    初探nginx架构(100%) 众所周知,nginx性能高,而nginx的高性能与其架构是分不开的.那么nginx究竟是怎么样的呢?这一节我们先来初识一下nginx框架吧. nginx在启动后,在un ...

  3. 初识Quartz(二)

    简单作业: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 package quartz_pr ...

  4. proxy_redirect参数的作用

    Nginx的代理功能太完善了,我们看看proxy_redirect参数的作用. 案例说明: 要做一个html.aslibra.com的域名处理很多网站的html内容,当然是后端的服务器了,目录分析 h ...

  5. 小程序swiper配置参数使用

    不管什么项目,一个轮播是基本少不了的,现在就来踩下微信小程序的swiper吧! 首先打开文档,可以看到下面这些参数:(https://mp.weixin.qq.com/debug/wxadoc/dev ...

  6. Chrome插件开发之manifest.json

    广而告之: Chrome插件之一键保存网页为PDF1.1发布 http://www.cnblogs.com/bdstjk/p/3179543.html 最近做“一键保存网页为PDF”过程中,对Chro ...

  7. SQL注入-数据库判断

    0x01.sql注入 sql注入是在系统开发的过程中程序员编程不规范,我们可以通过把SQL语句插入到WEB表单中进行查询字符串,最终达成欺骗服务器执行恶意的SQL命令.对于现在的网站SQL注入越来越严 ...

  8. Anaconda+Tensorflow环境安装与配置(转载)

    Anaconda+Tensorflow环境安装与配置 转载请注明出处:http://www.cnblogs.com/willnote/p/6746499.html Anaconda安装 在清华大学 T ...

  9. Unity3d中使用自带动画系统制作下雨效果(二)

    接着昨天的(一),今天上下雨效果的后半部分.在最后附上网盘链接,有使用的素材及本次的工程源文件,想看看的童鞋可以下载~~ 下雨效果分两部分:地上的涟漪和空中的雨滴.那么现在就开始,是使用unity3d ...

  10. 【Python + ATX基于uiautomator2】之编写unittest自动化测试脚本

    不说废话上代码: #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2018/08/31 09:43 # @Author : zc # @ ...