P3295 [SCOI2016] 萌萌哒 题解
题目链接
题目解法
暴力并查集 \(merge\) 肯定不可行
对于限制是 \(O(n^2)\) 的,查询却是 \(O(n)\),所以考虑均衡复杂度
可以用倍增的思想求解
令 \(fa_{i,j}\) 为 \([i,i+2^j-1]\) 的并查集数组,记录的是祖先的下标
这样限制不难做到 \(O(n\log n)\),即合并 \(\log\) 个并查集数组
考虑并查集的下传
即 \(fa_{p,i}=fa_{q,i}\) 时,需要使 \(fa_{p,i-1}=fa_{q,i-1}\) 且 \(fa_{p+2^{i-1},i-1}=fa_{q+2^{i-1},i-1}\)
这个可以直接 \(merge\) 实现,具体的看代码会清晰一点
时间复杂度 \(O(n\log n)\)
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
const int P=1e9+7,N=100100;
int n,m,fa[N][20];
bool tag[N];
int get_father(int x,int y){ return fa[x][y]==x?x:fa[x][y]=get_father(fa[x][y],y);}
void merge(int x,int y,int len){
int p=get_father(x,len),q=get_father(y,len);
if(p!=q) fa[p][len]=q;
}
int main(){
n=read(),m=read();
F(i,1,n) F(j,0,18) fa[i][j]=i;
F(i,1,m){
int l1=read(),r1=read(),l2=read(),r2=read();
DF(j,18,0) if(l1+(1<<j)-1<=r1) merge(l1,l2,j),l1+=1<<j,l2+=1<<j;
}
DF(i,18,1) F(j,1,n-(1<<i)+1){
int x=get_father(j,i);
merge(j,x,i-1),merge(j+(1<<(i-1)),x+(1<<(i-1)),i-1);
}
F(i,1,n) tag[get_father(i,0)]=1;
int cnt=-1;
F(i,1,n) if(tag[i]) cnt++;
int ans=9;
while(cnt--) ans=ans*10ll%P;
printf("%d\n",ans);
fprintf(stderr,"%d ms\n",int(1e3*clock()/CLOCKS_PER_SEC));
return 0;
}

浙公网安备 33010602011771号