#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);
}