【CF#715C】Digit Tree 点分治+乘法逆元
来源:互联网 发布:豆瓣fm for mac 编辑:程序博客网 时间:2024/06/05 14:53
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;}
0 0
- 【CF#715C】Digit Tree 点分治+乘法逆元
- HDU4812 D tree 【点分治 + 乘法逆元】
- CodeForces 715C Digit Tree (树的分治)
- 【Codeforces 715C&716E】Digit Tree【树分治】
- Codeforces Round #372 (Div. 1) C. Digit Tree(树的点分治)
- hdu4812 D Tree 【点分治+逆元+hash】
- HDU 4812 D Tree 点分治 + 逆元
- [Codeforces716E]Digit Tree(点分治+扩欧+二分)
- 【HDU4812】multik {树分治+乘法逆元}
- codeforces 715C. Digit Tree
- CF 327C 逆元
- CF 321C(Ciel the Commander-点分治)
- Codeforces Round #372 (Div. 2) E. Digit Tree (点分治)
- Codeforces Round #372 (Div. 2) E. Digit Tree(点分治,好题)
- [Poj1741]Tree (点分治)
- poj1741 Tree 点分治
- bzoj1468: Tree 点分治
- [POJ1741]Tree |点分治
- ARM:单和多寄存器加载存储、状态寄存器、协处理、软中断、乘法、交换等汇编指令
- 我的第一次——那一夜
- 最长对称子串
- DevExpress--TreeList
- Java的RMI远程方法调用实现和应用
- 【CF#715C】Digit Tree 点分治+乘法逆元
- 获取路径文件名
- CDOJ 251 导弹拦截 最长递增子序列
- XiaomiRouter自学之路(03-官方系统熟悉及备份)
- CppQuiz 系列3
- 吞吐量 截止时间 响应时间
- 图的存储方式一
- 解析文本文件 "r" 与 "rb" 模式的区别(Python)
- ICPC 2016 沈阳站 小记 [铁++ → 铁×2]