萌萌哒

以前是水的,写的玩意完全看不懂,这次认真写了写。

如果位置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;
}
posted @ 2021-03-11 21:47  liuzhaoxu  阅读(148)  评论(0编辑  收藏  举报