2018.09.14【BZOJ4596】【SCOI2016】萌萌哒(并查集)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/82710113

传送门


解析:

显然当我们统计出有多少个真正意义上互相独立的数位之后,这道题就只剩下一个快速幂的事情。

那么考虑怎么统计。

显然不可能是对于所有节点 O ( n ) 扫一遍建立并查集。

既然是区间。。。区间。。。

而且只有单纯的合并操作。

分层并查集!

f a [ i ] [ c ] 表示 i 在第 c 层里面的所属集合的根节点。
也就是保存以 i 为起点长度为 2 c 的区间与那些区间相同。

对于每一个限制,考虑像 S T 表一样拆成二进制。

最后 O ( n l o g n ) 向下递推一下。

而这里为了防止递推出锅。
我们规定在合并并查集的时候,都是从小的向大的合并。

最后在 f a [ i ] [ 0 ] 当中统计数位个数。
最后防止出现前导0对快速幂处理一下。


代码:

#include<bits/stdc++.h>
using namespace std;
#define re register
#define ll long long
#define gc getchar
#define pc putchar
#define cs const
#define st static
cs ll mod=1000000007;
inline
int getint(){
    st int num;
    st char c;
    for(c=gc();!isdigit(c);c=gc());
    for(num=0;isdigit(c);c=gc())num=(num<<1)+(num<<3)+(c^48);
    return num;
}

inline
void outint(ll a){
    st char ch[23];
    if(!a)pc('0');
    while(a)ch[++ch[0]]=(a-a/10*10)^48,a/=10;
    while(ch[0])pc(ch[ch[0]--]);
}

inline void swap(int &a,int &b){
    a^=b;
    b^=a;
    a^=b;
}

inline
ll quickpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}

int logn[100001];
int n,m;
int fa[100001][17];

inline
int getfa(int x,int c){
    while(x^fa[x][c])x=fa[x][c]=fa[fa[x][c]][c];return x;
}

inline
void merge(int x,int y,int c){
    st int fa_x,fa_y;
    if((fa_x = getfa(x, c)) == (fa_y = getfa(y, c))) return ;
    if(fa_x<fa_y)swap(fa_x,fa_y);
    fa[fa_x][c]=fa_y;
}

int main(){
    n=getint(),m=getint();
    for(int re i=2;i<=n;++i)logn[i]=logn[i>>1]+1; 
    for(int re i=1;i<=n;++i)
    for(int re j=0;j<=logn[n];++j)
    fa[i][j]=i;
    for(int re i=1;i<=m;++i){
        st int l1,l2,r1,r2,len;
        l1=getint();
        r1=getint();
        l2=getint();
        r2=getint();
        len=r1-l1+1;
        merge(l1,l2,logn[len]);
        merge(r1+1-(1<<logn[len]),r2+1-(1<<logn[len]),logn[len]);
    }
    for(int re j=logn[n];j;--j){
        for(int re l=1;l+(1<<j)-1<=n;++l){
            st int fa_l;
            if((fa_l=getfa(l,j))==l)continue;
            merge(fa_l,l,j-1);
            merge(fa_l+(1<<(j-1)),l+(1<<(j-1)),j-1);
        }
    }
    int cnt=0;
    for(int re i=1;i<=n;++i){
        if(fa[i][0]==i)++cnt;
    }
    outint(9ll*quickpow(10,cnt-1)%mod);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/82710113