zoukankan      html  css  js  c++  java
  • [SCOI2016]萌萌哒

    题目

    这也太妙啦

    首先这个题等价于问最后的联通块数量,一个非常显然的暴力就是暴力把两个区间的按位合并,自然是用并查集,复杂度(O(sum r_i-l_i+1))

    我们看到这个题大概在用并查集来维护连边,那么接下俩应该就是优化一下这个连边过程了,考虑一下分块,线段树以及倍增发现就倍增可行一些

    线段树和分块不可行的原因就是他们拆分区间的时候对于两段不同的区间可能拆出来的数量和每一段的长度不相同,这样非常不适于这道按位合并的题目

    于是考虑倍增,首先倍增拆出来的(log)段区间,每一段对应的长度都是相等的,考虑用并查集合并掉这两个区间,但是是对于每一个二次幂都有一个并查集

    比如说在第(k)个并查集里,(i)(j)在一个联通块里,只是说明了([i,i+2^k-1])([j,j+2^k-1])这两段区间是按位相等的

    我们从大到小一次扫二次幂的并查集,暴力扫一遍所有点,如果(k)层里(i,j)联通,那么显然等价于在(k-1)层里(i,j)联通,(i+2^{k-1},j+2^{k-1})联通,于是我们每次这样暴力把区间拆成两半,放到下一层去处理,当处理完(2^1)的时候,最底层的并查集就是我们需要的了

    这个思路还是相当妙的

    代码

    #include<bits/stdc++.h>
    #define re register
    #define pb push_back
    const int maxn=1e5+5;
    const int mod=1e9+7;
    inline int read() {
        char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
        while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n,m,l[2],r[2],vis[maxn];
    int fa[18][maxn],lg[maxn];
    std::vector<int> v[maxn];
    int find(int k,int x) {return fa[k][x]==x?x:fa[k][x]=find(k,fa[k][x]);}
    inline void merge(int k,int x,int y) {
        int xx=find(k,x),yy=find(k,y);
        if(xx==yy) return;
        fa[k][xx]=yy;
    }
    int main() {
        n=read(),m=read();
        for(re int i=2;i<=n;i++) lg[i]=lg[i>>1]+1;
        for(re int i=1;i<=n;i++)
    		for(re int j=0;i+(1<<j)-1<=n;j++) fa[j][i]=i;
        while(m--) {
    		l[0]=read(),r[0]=read(),l[1]=read(),r[1]=read();
    		int len=r[0]-l[0]+1;
    		for(re int k=lg[len];k>=0;--k)
    	    	if(l[0]+(1<<k)-1<=r[0]) 
    				merge(k,l[0],l[1]),l[0]+=(1<<k),l[1]+=(1<<k);
        }
        for(re int k=lg[n];k;--k) {
    		for(re int i=1;i<=n;i++)
    	    	v[find(k,i)].pb(i);
    		for(re int i=1;i<=n;i++) {
    	    	for(re int j=1;j<v[i].size();j++)
    				merge(k-1,v[i][j],v[i][j-1]);
    	    	for(re int j=1;j<v[i].size();j++)
    				merge(k-1,v[i][j]+(1<<(k-1)),v[i][j-1]+(1<<(k-1)));
    	    	v[i].clear();
    		}
        }
        int ans=-1,now=9;
        for(re int i=1;i<=n;i++) if(!vis[find(0,i)]) ++ans,vis[find(0,i)]=1;
        while(ans--) now=1ll*now*10%mod;
        printf("%d
    ",now);
        return 0;
    }
    
  • 相关阅读:
    通过web端启动关闭服务器程序以及检测程序运行状态
    Windows 自动监听程序,游戏服务器挂掉以后,自动监听程序将其重启起来
    自动监听程序,如果程序挂了,就重启
    删除log
    封装了一个C++类,当程序意外崩溃的时候可以生成dump文件,以便确定错误原因。
    贝塞尔曲线
    golang sql连接池 超时 数据库自动断开 ->127.0.0.1:3 306: wsarecv: An established connection was aborted by the software in your host machine.
    带控制的抢庄牛牛
    龙虎斗控制
    回归模型与房价预测
  • 原文地址:https://www.cnblogs.com/asuldb/p/11191431.html
Copyright © 2011-2022 走看看