#ST表,并查集#洛谷 3295 [SCOI2016]萌萌哒


题目


分析

可以发现除了最高位只能填 1 到 9,其它位置还可以填 0。

直接用并查集找连通块会超时,如果将这些区间的合并可以下传到子区间的合并那样就可以了。

考虑ST表的逆操作,合并时直接合并两个极大ST表的区间,然后再将这些合并下传到区间更小的位置即可


代码

#include 
#include 
using namespace std;
const int N=100011;
int f[N][17],lg[N],two[17],n,m,ans=1;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
int getf(int u,int d){return f[u][d]==u?u:f[u][d]=getf(f[u][d],d);}
void Merge(int x,int y,int z){
	int fa=getf(x,z),fb=getf(y,z);
	if (fa>1]+1;
	for (int j=0;j<=lg[n];++j)
	for (int i=1;i+two[j]-1<=n;++i) f[i][j]=i;
	for (int i=1;i<=m;++i){
		int lx=iut(),ly=iut(),rx=iut(),ry=iut(),z=lg[ly-lx+1];
		Merge(lx,rx,z),Merge(ly-two[z]+1,ry-two[z]+1,z);
	}
	for (int j=lg[n];j;--j)
	for (int i=1;i+two[j]-1<=n;++i){
		int now=getf(i,j);
		Merge(i,now,j-1),Merge(i+two[j-1],now+two[j-1],j-1);//右区间合并对应位置
	}
	for (int i=1,flag=1;i<=n;++i) if (getf(i,0)==i)
	    ans=(10ll-flag)*ans%1000000007,flag=0;
	return !printf("%d",ans);
}

相关