版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82710113
解析:
显然当我们统计出有多少个真正意义上互相独立的数位之后,这道题就只剩下一个快速幂的事情。
那么考虑怎么统计。
显然不可能是对于所有节点 扫一遍建立并查集。
既然是区间。。。区间。。。
而且只有单纯的合并操作。
分层并查集!
令
表示
在第
层里面的所属集合的根节点。
也就是保存以
为起点长度为
的区间与那些区间相同。
对于每一个限制,考虑像 表一样拆成二进制。
最后 向下递推一下。
而这里为了防止递推出锅。
我们规定在合并并查集的时候,都是从小的向大的合并。
最后在
当中统计数位个数。
最后防止出现前导0对快速幂处理一下。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define gc getchar
#define pc putchar
#define cs const
#define st static
cs ll mod=1000000007;
inline
int getint(){
st int num;
st char c;
for(c=gc();!isdigit(c);c=gc());
for(num=0;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
return num;
}
inline
void outint(ll a){
st char ch[23];
if(!a)pc('0');
while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
while(ch[0])pc(ch[ch[0]--]);
}
inline void swap(int &a,int &b){
a^=b;
b^=a;
a^=b;
}
inline
ll quickpow(ll a,ll b){
ll ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
int logn[100001];
int n,m;
int fa[100001][17];
inline
int getfa(int x,int c){
while(x^fa[x][c])x=fa[x][c]=fa[fa[x][c]][c];return x;
}
inline
void merge(int x,int y,int c){
st int fa_x,fa_y;
if((fa_x = getfa(x, c)) == (fa_y = getfa(y, c))) return ;
if(fa_x<fa_y)swap(fa_x,fa_y);
fa[fa_x][c]=fa_y;
}
int main(){
n=getint(),m=getint();
for(int re i=2;i<=n;++i)logn[i]=logn[i>>1]+1;
for(int re i=1;i<=n;++i)
for(int re j=0;j<=logn[n];++j)
fa[i][j]=i;
for(int re i=1;i<=m;++i){
st int l1,l2,r1,r2,len;
l1=getint();
r1=getint();
l2=getint();
r2=getint();
len=r1-l1+1;
merge(l1,l2,logn[len]);
merge(r1+1-(1<<logn[len]),r2+1-(1<<logn[len]),logn[len]);
}
for(int re j=logn[n];j;--j){
for(int re l=1;l+(1<<j)-1<=n;++l){
st int fa_l;
if((fa_l=getfa(l,j))==l)continue;
merge(fa_l,l,j-1);
merge(fa_l+(1<<(j-1)),l+(1<<(j-1)),j-1);
}
}
int cnt=0;
for(int re i=1;i<=n;++i){
if(fa[i][0]==i)++cnt;
}
outint(9ll*quickpow(10,cnt-1)%mod);
return 0;
}