zoukankan      html  css  js  c++  java
  • CF1375H Set Merging 题解

    Codeforces
    Luogu

    Description.

    有一个长度为 \(n(n\le 2^{12})\) 排列,和 \(Q(Q\le 2^{16})\) 个要求。
    初始有 \(\{\{a_1\},\{a_2\},\cdots,\{a_n\}\}\) 这个大集合。
    有一种操作:

    • 选择 \(S,T\) 两个集合,满足 \(\max\{S\}\le \min\{T\}\),把 \(S\cup T\) 加入大集合。

    每个要求形如:

    • 在大集合中存在 \([l,r]\) 所有数构成的集合。

    在每个瞬间最多只能有 \(2.2\times 10^6\) 个集合。

    Solution.

    \(2^{21}\approx 2\times 10^6\),猜测最后复杂度是 \(O(2n\sqrt q)\) 的。

    对于每个询问,会被拆成 \(\frac nB\) 个块,如果我们每个块所对应的子区间全都处理好就可以 \(O(\frac nB)\) 合并,总复杂度 \(O(\frac{qn}B)\)

    值域分块,对于每个块内先合并出每个子区间,要求总复杂度 \(O(\frac nB\times B^2)=O(nB)\)
    考虑值域分治,两个子问题很好处理,然后合并直接 \(O(n^2)\) 合并,复杂度 \(O(T)=2O(\frac T2)+O(n^2)=O(n^2)\),总复杂度 \(O(\frac nBB^2)=O(nB)\)

    \(B=\sqrt Q\) 时最优,总复杂度为 \(O(2n\sqrt q)\)

    Coding.

    刚开始每个块里开了 \(B*B\) 的静态数组,MLE 了,以为是这个的锅,就换成 vector 了

    点击查看代码
    #include<bits/stdc++.h>//{{{
    using namespace std;typedef long long ll;
    template<typename T>inline void read(T &x)
    {
        x=0;char c=getchar(),f=0;
        for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1;
        for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48);
        f?x=-x:x;
    }
    template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}/*}}}*/
    const int N=1<<12|5,B=1<<8,Lim=2.2e6;
    int n,q,a[N],wh[N],rsx[Lim],rsy[Lim],rst,rsid[1<<16|5];
    inline int mrg(int x,int y) {return !x||!y?x|y:(rsx[++rst]=x,rsy[rst]=y,rst);}
    struct block
    {
    	int len,pos[B+5];vector<vector<int> >id;
    	inline void init(int x) {len=x,id.resize(x+1);for(int i=1;i<=x;i++) id[i].resize(x+1);}
    	block(int x=0) {if(x) init(1),id[1][1]=pos[1]=wh[x];}
    	inline int qryid(int l,int r)
    	{//这个是值域区间
    		if(r<pos[1]||l>pos[len]) return 0;
    		int le=lower_bound(pos+1,pos+len+1,l)-pos;
    		int ri=upper_bound(pos+1,pos+len+1,r)-pos-1;
    		return le>ri?0:id[le][ri];
    	}
    	inline block operator+(block y)
    	{
    		block rs;rs.init(len+y.len);//guard that *this < y
    		for(int i=1;i<=len;i++) rs.pos[i]=pos[i];
    		for(int i=1;i<=y.len;i++) rs.pos[i+len]=y.pos[i];
    		sort(rs.pos+1,rs.pos+rs.len+1);
    		for(int i=1;i<=rs.len;i++) for(int j=i;j<=rs.len;j++)
    			rs.id[i][j]=mrg(qryid(rs.pos[i],rs.pos[j]),y.qryid(rs.pos[i],rs.pos[j]));
    		return rs;
    	}
    	inline void output()
    	{
    		puts("-----------------------------------------");
    		printf("seg : %d\nthe val : ",len);
    		for(int i=1;i<=len;i++) printf("%d%c",pos[i],i==len?'\n':' ');
    		for(int i=1;i<=len;i++) for(int j=i;j<=len;j++) printf("%d%c",id[i][j],j==len?'\n':' ');
    		puts("-----------------------------------------");
    	}
    }A[N/B+5];
    inline block solve(int l,int r)
    {//值域区间
    	int md=(l+r)>>1;if(l==r) return block(l);
    	return solve(l,md)+solve(md+1,r);
    }
    int main()
    {
    	read(n,q),rst=n;for(int i=1;i<=n;i++) read(a[i]),wh[a[i]]=i;
    	for(int i=0;i<=(n-1)/B;i++) A[i]=solve(i*B+1,min(i*B+B,n));
    	for(int k=1,l,r;k<=q;k++)
    	{
    		read(l,r),rsid[k]=0;
    		for(int i=0;i<=(n-1)/B;i++) rsid[k]=mrg(rsid[k],A[i].qryid(l,r));
    	}
    	printf("%d\n",rst);for(int i=n+1;i<=rst;i++) printf("%d %d\n",rsx[i],rsy[i]);
    	for(int i=1;i<=q;i++) printf("%d%c",rsid[i],i==q?'\n':' ');
    	return 0;
    }
    
  • 相关阅读:
    win10家庭版安装Docker for Windows
    docker镜像拉取速度过慢的解决
    解决docker: error pulling image configuration: Get https://registry-1.docker.io/v2/library/mysql/: TLS handshake timeout.
    ubuntu16.04下安装docker
    Ubuntu 16.04执行 sudo apt-get update非常慢解决方案
    [转载]MySQL存储过程详解  mysql 存储过程
    除非 Windows Activation Service (WAS)和万维网发布服务(W3SVC)均处于运行状态,
    windows资源管理器已经停止工作
    Shell脚本sqlldr导入数据压缩文件截断
    oracle 日常运维
  • 原文地址:https://www.cnblogs.com/pealfrog/p/15416440.html
Copyright © 2011-2022 走看看