[BZOJ4569] [Scoi2016]萌萌哒

余生颓废 提交于 2019-12-01 22:55:24

[BZOJ4569][Scoi2016]萌萌哒

好题!

倍增维护并查集合并

一个倍增数组\(fa[i][j]\)维护从\(i\)开始长度为\(2^j\)的这一段与那一段长度相同的并在一起

将两端区间\(l1,r2,l2,r2\)用倍增剖开,在那一层的倍增数组上用并查集合并

最后每次将\(fa[i][j]\)\(fa[i][j-1],fa[i+(1<<(j-1))][j-1]\)递推即可

int n,m;
struct UFS{
    int fa[N];
    int Find(int x) { return fa[x]==x?x:fa[x]=Find(fa[x]); }
    void init(){ rep(i,1,n) fa[i]=i; }
    void merge(int x,int y) { 
        fa[Find(x)]=Find(y);
    }
} B[18];
int LOG;
int main(){
    n=rd(),m=rd();
    for(LOG=0;(1<<LOG)<=n;LOG++) B[LOG].init();
    LOG--;
    rep(i,1,m) {
        int l1=rd(),r1=rd();
        int l2=rd();rd();
        if(l1==l2) continue;
        int len=r1-l1+1;
        drep(j,LOG,0) {
            if(len>=(1<<j)) {
                B[j].merge(l1,l2);
                l1+=1<<j,l2+=1<<j;
                len-=1<<j;
            }
        }
    }
    drep(i,LOG,1) {
        int len=(1<<(i-1));
        rep(j,1,n) {
            int f=B[i].Find(j);
            B[i-1].merge(j,f);
            B[i-1].merge(j+len,f+len);
        }
    }
    int cnt=0;
    rep(i,1,n) if(B[0].Find(i)==i) cnt++;
    ll ans=1;
    rep(i,1,cnt-1) ans=ans*10%P;
    ans=ans*9%P;
    printf("%lld\n",ans);
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!