[BZOJ4569][Scoi2016]萌萌哒
好题!
倍增维护并查集合并
一个倍增数组\(fa[i][j]\)维护从\(i\)开始长度为\(2^j\)的这一段与那一段长度相同的并在一起
将两端区间\(l1,r2,l2,r2\)用倍增剖开,在那一层的倍增数组上用并查集合并
最后每次将\(fa[i][j]\)向\(fa[i][j-1],fa[i+(1<<(j-1))][j-1]\)递推即可
int n,m; struct UFS{ int fa[N]; int Find(int x) { return fa[x]==x?x:fa[x]=Find(fa[x]); } void init(){ rep(i,1,n) fa[i]=i; } void merge(int x,int y) { fa[Find(x)]=Find(y); } } B[18]; int LOG; int main(){ n=rd(),m=rd(); for(LOG=0;(1<<LOG)<=n;LOG++) B[LOG].init(); LOG--; rep(i,1,m) { int l1=rd(),r1=rd(); int l2=rd();rd(); if(l1==l2) continue; int len=r1-l1+1; drep(j,LOG,0) { if(len>=(1<<j)) { B[j].merge(l1,l2); l1+=1<<j,l2+=1<<j; len-=1<<j; } } } drep(i,LOG,1) { int len=(1<<(i-1)); rep(j,1,n) { int f=B[i].Find(j); B[i-1].merge(j,f); B[i-1].merge(j+len,f+len); } } int cnt=0; rep(i,1,n) if(B[0].Find(i)==i) cnt++; ll ans=1; rep(i,1,cnt-1) ans=ans*10%P; ans=ans*9%P; printf("%lld\n",ans); }