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

posted @ 2023-11-30 08:47  Farmer_D  阅读(33)  评论(0)    收藏  举报