zoukankan      html  css  js  c++  java
  • [Ynoi2018]未来日记(分块)

    分块神题。

    看了一会儿题解,看懂了思路,然后写了两个小时,调了一个多小时,好多地方写错了。

    我们考虑对序列和值域都分块。(sum1[i][j]) 表示前 (i) 个块,第 (j) 块值域有几个数,(sum2[i][j]) 表示前 (i) 个块,值为 (j) 有几个数,(id[i][j]) 表示第 (i) 块值为 (j) 的编号,(mp[i][j]) 表示第 (i) 块编号为 (j) 值为多少,这样空间正好开的下。

    对于修改操作,我们考虑边角暴力。在整块中若只有 (x) 那么直接修改,若又有 (y) 的话就暴力重构。每次重构整块中不同的数的数目会 (-1),一个块最多被重构 (sqrt{n}) 块,所以时间复杂度保证为 (O(nsqrt{n}))

    对于询问操作,我们利用 (sum1)(sum2) 可以在 (O(sqrt{n})) 得到。

    时间复杂度 (O(nsqrt{n})),空间复杂度 (O(nsqrt{n}))

    洛谷加了 (fread,fwrite) 才卡过去,空间差点 (MLE)。。。

    (Code Below:)

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=100000+10;
    const int maxblo=317;
    const int lim=100000;
    int n,m,blo,a[maxn],pos[maxn],bl[maxn],L[maxn],R[maxn];
    int v1[maxn],v2[maxn],sum1[maxblo][maxblo],sum2[maxblo][maxn],id[maxblo][maxn],mp[maxblo][maxblo];
    
    namespace FastIO{
    	#define gc() (iS==iT?(iT=(iS=ibuff)+fread(ibuff,1,SIZ,stdin),(iS==iT?EOF:*iS++)):*iS++)
    	const int SIZ=1<<21|1;
    	char *iS,*iT,ibuff[SIZ],obuff[SIZ],*oS=obuff,*oT=oS+SIZ-1,fu[110],c;int fr;
    	inline void out(){
    		fwrite(obuff,1,oS-obuff,stdout);
    		oS=obuff;
    	}
    	template <class T>
    	inline void read(T &x){
    		x=0;T y=1;
    		for(c=gc();(c>'9'||c<'0')&&c!='-';c=gc());
    		c=='-'?y=-1:x=(c&15);
    		for(c=gc();c>='0'&&c<='9';c=gc()) x=x*10+(c&15);
    		x*=y;
    	}
    	template <class T>
    	inline void print(T x,char text='
    '){
    		if(x<0) *oS++='-',x*=-1;
    		if(x==0) *oS++='0';
    		while(x) fu[++fr]=x%10+'0',x/=10;
    		while(fr) *oS++=fu[fr--];
    		*oS++=text;out();
    	}
    }
    using namespace FastIO;
    
    inline void reset(int x){
    	for(int i=L[x];i<=R[x];i++) a[i]=mp[x][pos[i]];
    }
    
    inline void change(int bel,int x,int y){
    	int last=id[bel][x];id[bel][y]=last;
    	mp[bel][last]=y;id[bel][x]=0;
    }
    
    inline void build(int x){
    	for(int i=1;i<=blo;i++) id[x][mp[x][i]]=0;
    	int ind=0;
    	for(int i=L[x];i<=R[x];i++)
    		if(!id[x][a[i]]) id[x][a[i]]=++ind,mp[x][ind]=a[i];
    	for(int i=L[x];i<=R[x];i++) pos[i]=id[x][a[i]];
    }
    
    inline void rebuild(int l,int x,int y){
    	for(int i=bl[l];i<=bl[n];i++){
    		sum1[i][bl[x]]+=sum1[i-1][bl[x]];
    		sum1[i][bl[y]]+=sum1[i-1][bl[y]];
    		sum2[i][x]+=sum2[i-1][x];
    		sum2[i][y]+=sum2[i-1][y];
    	}
    }
    
    inline void modify(int l,int r,int x,int y){
    	if(sum2[bl[r]][x]==sum2[bl[l]-1][x]) return ;
    	for(int i=bl[n];i>=bl[l];i--){
    		sum1[i][bl[x]]-=sum1[i-1][bl[x]];
    		sum1[i][bl[y]]-=sum1[i-1][bl[y]];
    		sum2[i][x]-=sum2[i-1][x];
    		sum2[i][y]-=sum2[i-1][y];
    	}
    	if(bl[l]==bl[r]){
    		reset(bl[l]);
    		for(int i=l;i<=r;i++)
    			if(a[i]==x){
    				a[i]=y;
    				sum1[bl[l]][bl[x]]--;
    				sum1[bl[l]][bl[y]]++;
    				sum2[bl[l]][x]--;
    				sum2[bl[l]][y]++;
    			}
    		build(bl[l]);rebuild(l,x,y);
    		return ;
    	}
    	reset(bl[l]);reset(bl[r]);
    	for(int i=l;i<=R[bl[l]];i++)
    		if(a[i]==x){
    			a[i]=y;
    			sum1[bl[l]][bl[x]]--;
    			sum1[bl[l]][bl[y]]++;
    			sum2[bl[l]][x]--;
    			sum2[bl[l]][y]++;
    		}
    	for(int i=L[bl[r]];i<=r;i++)
    		if(a[i]==x){
    			a[i]=y;
    			sum1[bl[r]][bl[x]]--;
    			sum1[bl[r]][bl[y]]++;
    			sum2[bl[r]][x]--;
    			sum2[bl[r]][y]++;
    		}
    	build(bl[l]);build(bl[r]);
    	for(int i=bl[l]+1;i<bl[r];i++){
    		if(!sum2[i][x]) continue;
    		if(sum2[i][y]){
    			reset(i);
    			for(int j=L[i];j<=R[i];j++)
    				if(a[j]==x){
    					a[j]=y;
    					sum1[i][bl[x]]--;
    					sum1[i][bl[y]]++;
    					sum2[i][x]--;
    					sum2[i][y]++;
    				}
    			build(i);
    		}
    		else {
    			sum1[i][bl[x]]-=sum2[i][x];
    			sum1[i][bl[y]]+=sum2[i][x];
    			sum2[i][y]+=sum2[i][x];
    			sum2[i][x]=0;
    			change(i,x,y);
    		}
    	}
    	rebuild(l,x,y);
    }
    
    inline int query(int l,int r,int k){
    	if(bl[l]==bl[r]){
    		reset(bl[l]);
    		for(int i=l;i<=r;i++) v1[i]=a[i];
    		nth_element(v1+l,v1+l+k-1,v1+r+1);
    		int ans=v1[l+k-1];
    		for(int i=l;i<=r;i++) v1[i]=0;
    		return ans;
    	}
    	reset(bl[l]);reset(bl[r]);
    	for(int i=l;i<=R[bl[l]];i++) v1[bl[a[i]]]++,v2[a[i]]++;
    	for(int i=L[bl[r]];i<=r;i++) v1[bl[a[i]]]++,v2[a[i]]++;
    	for(int i=1;i<=bl[lim];i++){
    		if(k>v1[i]+sum1[bl[r]-1][i]-sum1[bl[l]][i]) k-=v1[i]+sum1[bl[r]-1][i]-sum1[bl[l]][i];
    		else {
    			for(int j=(i-1)*blo+1;j<=i*blo;j++){
    				if(k>v2[j]+sum2[bl[r]-1][j]-sum2[bl[l]][j]) k-=v2[j]+sum2[bl[r]-1][j]-sum2[bl[l]][j];
    				else {
    					for(int x=l;x<=R[bl[l]];x++) v1[bl[a[x]]]--,v2[a[x]]--;
    					for(int x=L[bl[r]];x<=r;x++) v1[bl[a[x]]]--,v2[a[x]]--;
    					return j;
    				}
    			}
    		}
    	}
    }
    
    int main()
    {
    	read(n),read(m);blo=sqrt(lim)+1;
    	for(int i=1;i<=n;i++) read(a[i]);
    	for(int i=1;i<=lim;i++){
    		bl[i]=(i-1)/blo+1;
    		if(bl[i]!=bl[i-1]) L[bl[i]]=i,R[bl[i-1]]=i-1;
    	}
    	R[bl[n]]=n;
    	for(int i=1;i<=bl[n];i++) build(i);
    	for(int x=1;x<=bl[n];x++){
    		for(int i=1;i<=bl[lim];i++) sum1[x][i]=sum1[x-1][i];
    		for(int i=1;i<=lim;i++) sum2[x][i]=sum2[x-1][i];
    		for(int i=L[x];i<=R[x];i++) sum1[x][bl[a[i]]]++,sum2[x][a[i]]++;
    	}
    	int op,l,r,x,y;
    	while(m--){
    		read(op),read(l),read(r),read(x);
    		if(op==1) read(y),modify(l,r,x,y);
    		else print(query(l,r,x));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Python学习笔记(十四)—hashlib模块
    Python学习笔记(十三)—函数常用模块
    Python学习笔记(十二)—函数
    PHP-代码执行
    CVE-2020-5902 F5 BIG-IP RCE复现
    sqli-Mysql写shell/读文件
    Mysql服务端反向读取客户端的任意文件
    PHP-AJAX
    PHP-XML
    googlehacking
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10324780.html
Copyright © 2011-2022 走看看