题意
在某些区间必须一样的情况下,可以组成多少个大数。
思路
将询问区间拆分成 若干个小区间,将 区间与区间 合并,最后计算答案时 将区间的信息下放到点上。
具体的来讲: 表示左端点为位置 ,长度为 的区间所在集合的根的左端点。
最终计算答案时,将所有层的对应端点合并即可,做法是将每层和他的上层合并 即将 与 合并,将 与 合并。
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=1e5+5,mod=1e9+7; int n,m,fa[N][18],ans; inline int read() { register int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();} while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x*f; } int find(int x,int k) { return fa[x][k]==x?x:fa[x][k]=find(fa[x][k],k); } void merge(int x,int y,int k) { x=find(x,k),y=find(y,k); if(x!=y)fa[x][k]=y; } int main() { n=read();m=read(); int py=floor(log2(n)); for(int i=1;i<=n;i++) for(int k=0;k<=py;k++) fa[i][k]=i; for(int i=1;i<=m;i++) { int l1=read(),r1=read(),l2=read(),r2=read(); for(int k=py;~k;k--) if(l1+(1<<k)-1<=r1) merge(l1,l2,k),l1+=1<<k,l2+=1<<k; } for(int k=py;k;k--) for(int i=1;i+(1<<k)-1<=n;i++) { int pos=find(i,k); merge(i,pos,k-1),merge(i+(1<<k-1),pos+(1<<k-1),k-1); } for(int i=1;i<=n;i++) if(fa[i][0]==i) ans=!ans?9:ans*10ll%mod; printf("%d",ans); return 0; }