#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<cstring>
#define mod 1000000007
using namespace std;
const int maxn = 1000007;
typedef long long ll;
ll f[maxn*10],st[maxn][25],position[maxn*10];
ll n,m,cnt;
int find(int x){return (f[x]==x)?x:f[x]=find(f[x]);}
void merge(int p1,int p2,int mi)
{
int f1=find(st[p1][mi]),f2=find(st[p2][mi]);
f[max(f1,f2)]=min(f1,f2); // 根据预处理的顺序来定,因为下面分裂区间要使用
return ; // 这里必须大的连小的
}
int main()
{
scanf("%lld%lld",&n,&m);
for(int i=1;i<=n;i++) // 并查集正常预处理
{
for(int j=0;j<=log2(n)+1;j++)
{
st[i][j]=++cnt;
position[cnt]=i;
f[cnt]=cnt;
}
}
for(int i=1;i<=m;i++) // 区间拆解 ,个人理解为后面st表的前提,详情见st预处理
{
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
for(int j=log2(n)+1;j>=0;j--) //LCA 渐进法
{
if(l1+(1<<j)-1<=r1) // l1 l2 r1 r2同步 只判断一个就可以
{
merge(l1,l2,j); // 可理解为当前位置点的严格合并前提,在此之后可以通过分裂
l1+=(1<<j); // 统计底层所需数据,达成查找目的
l2+=(1<<j);
}
}
}
for(int j=log2(n)+1;j>=1;j--) // j只能到1 因为会向下裂一步
{
for(int i=1;i+(1<<j)-1<=n;i++)
{
int fa=find(f[st[i][j]]),pp=position[fa]; // 如果没有经过上面那个循环的话,就变成了自己和自己相等
merge(i,pp,j-1); // 不损伤答案
merge(i+(1<<(j-1)),pp+(1<<(j-1)),j-1); // 合并
}
}
long long ans=9;
for(int i=2;i<=n;i++)// 第一位不可以选十个,所以ans起始为9
{
if(f[st[i][0]]==st[i][0])
{
ans*=10;
ans%=mod;
}
}
cout<<ans%mod;
}
08-26
07-11
“相关推荐”对你有帮助么?
-
非常没帮助
-
没帮助
-
一般
-
有帮助
-
非常有帮助
提交