題目鏈接
解法:倍增+並查集
先想暴力的做法。每次讀入,令從枚舉到,然後用並查集合並和,最後統計並查集中聯通塊的個數,答案即爲。
但是這樣會TLE。
對暴力進行優化。更改並查集中數組的含義,令表示從到這兩段的共同編號,亦即若則表示和這兩段數每項分別處於相同的聯通塊中。合併時用倍增的處理方式(參考ST表)。
代碼
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
const long long p=1000000007ll;
long long ans=1ll;
int n,m,l1,l2,r1,r2,f[17][100001];
bool flag=false;
int find(int x,int k){
return f[k][x]==x?x:f[k][x]=find(f[k][x],k);
}
void merge(int x,int y,int k){
if(y>100000)return;
int fx=find(x,k),fy=find(y,k);
if(fx!=fy)f[k][fx]=fy;
}
void update(int a,int b,int c,int d){
int k=(int)log2(b-a+1);
merge(a,c,k),merge(b-(1<<k)+1,d-(1<<k)+1,k);
}
int main(){
scanf("%d%d",&n,&m);int l=(int)log2(n);
for(int i=1;i<=n;++i)for(int k=0;k<17;++k)f[k][i]=i;
for(int i=1;i<=m;++i)scanf("%d%d%d%d",&l1,&r1,&l2,&r2),update(l1,r1,l2,r2);
for(int i=l;i;--i)for(int j=1;j<=n-(1<<i)+1;++j){int f=find(j,i);merge(j,f,i-1),merge(j+(1<<i-1),f+(1<<i-1),i-1);}
for(int i=1;i<=n;++i)if(find(i,0)==i)(ans*=(flag?10:((flag=true),9)))%=p;
printf("%lld",ans);
}