萌萌哒
以前是水的,写的玩意完全看不懂,这次认真写了写。
如果位置x,y上的数一样,我们可以用并查集将它们连起来,最终查询联通块个数cnt,答案就是 \(9*10^{cnt-1}\)
这样做复杂度是nmO(并查集常数)的,考虑优化
我们用倍增st表的思想,因为给出的总是两段区间相等,所以我们可以直接把这两端区间合并,表示这两段区间对应的数相等,
但是我们不能没有规律的合并,也就是不能他给你多长区间,你就把多长区间合并,我们跟st表一样,将区间按2的整数次幂合并,最后统一下放到最小区间fa[x][0]即可
复杂度 \(O(nlog^2n)\)
Code
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=1e5+10;
const int mod=1e9+7;
int n,m,ans,fa[maxn][20],lg[maxn];
int read(int x=0,bool f=0,char ch=getchar()){
for(;ch<'0' || ch>'9';ch=getchar()) f=ch=='-';
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch&15);
return f?-x:x;
}
int findrt(int x,int d){
return fa[x][d]==x?x:fa[x][d]=findrt(fa[x][d],d);
}
void merge(int x,int y,int d){
x=findrt(x,d),y=findrt(y,d);
if(x!=y) fa[x][d]=y;
}
int main(){
n=read(),m=read();
for(int i=2;i<=n;++i) lg[i]=lg[i/2]+1;
for(int i=1;i<=n;++i)
for(int j=0;j<=lg[n];++j)
fa[i][j]=i;
for(int i=1;i<=m;++i){
int l1=read(),r1=read(),l2=read(),r2=read();
int d=lg[r1-l1+1];
merge(l1,l2,d);
merge(r1+1-(1<<d),r2+1-(1<<d),d);
}
for(int i=lg[n];i>=1;--i){ // 注意倒序下放
for(int j=1;j+(1<<i)-1<=n;++j){
int x=findrt(j,i);
if(x==j) continue;
merge(j,x,i-1);
merge(j+(1<<(i-1)),x+(1<<(i-1)),i-1);
}
}
for(int i=1;i<=n;++i)
if(findrt(i,0)==i)
ans=(!ans?9:(ll)ans*10%mod);
printf("%d\n",ans);
return 0;
}