zoukankan      html  css  js  c++  java
  • [Ynoi2018]未来日记

    卡常有风险,code需谨慎

    题意:
    一个长为(n)的序列(a),有(m)次操作

    1. 把区间([l,r])内所有x变成y
    2. 查询区间([l,r])内k小值
      ((n leq 100000))

    题解:lxl所谓的“望月悲叹的第一分块”。
    其实就是将数列进行值域分块,同时将数列分块,令 (sum1[i][j])表示前(i)个块里值域在范围(( (j-1)*blocksize, j*blocksize ])的数的个数,(sum2[i][j])表示前(i)个块里值域为(j)的数的个数,空间开的下。
    将在同一个块里的数按顺序从左往右编号,保证权值相同的数编号唯一,同时记录(rid)表示该块中编号对应的权值。

    对于修改操作,先将所有受影响的前缀和操作撤销,对于边角块,暴力重构修改并重新纪录,对于整块分两种情况:若这个块中有权值为(x)的数且没有权值为(y)的数,将它的(rid)存储信息转移到(y)里;若这个块中有权值为(x)的数且有权值为(y)的数,将其暴力重构修改并重新记录,由于一次这样的重构会使这个块内不同权值的数目减(1),所以一个块最多这样重构(sqrt {n})次,将整个序列这样重构时间复杂度为(O(n sqrt {n}))

    对于询问操作,两个边角块另开两个数组(s1[])(s2[]),作用与之前的(sum1[i][j])(sum2[i][j])一样。由于有前缀和操作,所以查询区间任意值域或权值数的个数仅需(O(1))的时间。询问先早答案暴力从小到大枚举在哪一个值域里,然后在值域里暴力枚举答案即可。

    总时间(O(n sqrt {n}))

    代码:

    #include<bits/stdc++.h>
    #pragma GCC optimize(3)//卡常
    using namespace std;
    const int N=110010,BLO=370;
    int n,m,a[N],p,vec[N],v2[BLO];
    int bl[N],L[BLO],R[BLO];
    int s1[BLO][BLO],s2[BLO][N],id[BLO][N],rid[BLO][BLO],pos[N];//此处s1为sum1,s2为sum2
    int sta[20],ttop=0,lp=0;
    char pr[700010];//输出卡常(不会fread)
    
    template <typename T> inline void read(T &x) {
    	x=0;register char flag,c=getchar();while(c<'0'||c>'9')	flag=c,c=getchar();
    	while(c>='0'&&c<='9')	x=x*10+(c^48),c=getchar(); if(flag=='-') x=-x;
    }
    template <typename T> inline void print(T x) {
    	ttop=0; do { sta[++ttop]=(int)(x%10),x/=10; }while(x);
    	while(ttop)	pr[lp++]=sta[ttop--]+'0'; pr[lp++]=10;
    }
    void reset(int x) { for(register int i=L[x];i<=R[x];++i)	a[i]=rid[x][pos[i]]; }
    void change(int bel,int x,int y) {
    	int uid=id[bel][x];id[bel][y]=uid,rid[bel][uid]=y,id[bel][x]=0;
    }
    void build(int x) {
    	for(register int i=1;i<=p;++i)	id[x][rid[x][i]]=0;
    	for(register int i=L[x],idx=0;i<=R[x];++i)
    		if(!id[x][a[i]])
    			id[x][a[i]]=++idx,rid[x][idx]=a[i];
    	for(register int i=L[x];i<=R[x];++i)	pos[i]=id[x][a[i]];
    }
    void rebuild(int l,int x,int y) {
    	for(register int i=bl[l];i<=bl[n];++i) {
    		s2[i][x]+=s2[i-1][x],s2[i][y]+=s2[i-1][y];
    		s1[i][bl[x]]+=s1[i-1][bl[x]],s1[i][bl[y]]+=s1[i-1][bl[y]];
    	}
    }
    void modify(int l,int r,int x,int y) {
    	if(s2[bl[r]][x]-s2[bl[l]-1][x]==0)	return ;
    	for(int i=bl[n];i>=bl[l];--i) {
    		s2[i][x]-=s2[i-1][x],s2[i][y]-=s2[i-1][y];
    		s1[i][bl[x]]-=s1[i-1][bl[x]],s1[i][bl[y]]-=s1[i-1][bl[y]];
    	}
    	if(bl[l]==bl[r]) {
    		reset(bl[l]);
    		for(int i=l;i<=r;++i)
    			if(a[i]==x) {
    				a[i]=y;
    				--s2[bl[l]][x],++s2[bl[l]][y];
    				--s1[bl[l]][bl[x]],++s1[bl[l]][bl[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;
    			--s2[bl[l]][x],++s2[bl[l]][y];
    			--s1[bl[l]][bl[x]],++s1[bl[l]][bl[y]];
    		}
    	for(int i=L[bl[r]];i<=r;++i)
    		if(a[i]==x) {
    			a[i]=y;
    			--s2[bl[r]][x],++s2[bl[r]][y];
    			--s1[bl[r]][bl[x]],++s1[bl[r]][bl[y]];
    		}
    	build(bl[l]),build(bl[r]);
    	for(int i=bl[l]+1;i<bl[r];++i) {
    		if(!s2[i][x])	continue;
    		if(s2[i][y]) {
    			reset(i);
    			for(int j=L[i];j<=R[i];++j)
    				if(a[j]==x) {
    					a[j]=y;
    					--s2[i][x],++s2[i][y];
    					--s1[i][bl[x]],++s1[i][bl[y]];
    				}
    			build(i);
    		}
    		else {
    			s1[i][bl[y]]+=s2[i][x],s1[i][bl[x]]-=s2[i][x];
    			s2[i][y]+=s2[i][x],s2[i][x]=0;
    			change(i,x,y);
    		}
    	}
    	rebuild(l,x,y);
    }
    int ask(int l,int r,int k) {
    	int ans=0,sum=0;
    	if(bl[l]==bl[r]) {
    		reset(bl[l]);for(int i=l;i<=r;++i)	vec[i]=a[i];
    		nth_element(vec+l,vec+l+k-1,vec+r+1),ans=vec[l+k-1];
    		for(int i=l;i<=r;++i)	vec[i]=0; return ans;
    	}
    	reset(bl[l]),reset(bl[r]);
    	for(int i=l;i<=R[bl[l]];++i)	++vec[a[i]],++v2[bl[a[i]]];
    	for(int i=L[bl[r]];i<=r;++i)	++vec[a[i]],++v2[bl[a[i]]];
    	for(int i=1;i<=bl[N-1];++i) {
    		if(sum+v2[i]+s1[bl[r]-1][i]-s1[bl[l]][i]>=k) {
    			for(int j=(i-1)*p+1;j<=i*p;j++) {
    				if(vec[j]+s2[bl[r]-1][j]-s2[bl[l]][j]+sum>=k) { ans=j;goto FLAG; }
    				else	sum+=vec[j]+s2[bl[r]-1][j]-s2[bl[l]][j];
    			}
    		}
    		else	sum+=v2[i]+s1[bl[r]-1][i]-s1[bl[l]][i];
    	}
    	FLAG:
    	for(int i=l;i<=R[bl[l]];++i)	--vec[a[i]],--v2[bl[a[i]]];
    	for(int i=L[bl[r]];i<=r;++i)	--vec[a[i]],--v2[bl[a[i]]];
    	return ans;
    }
    int main() {
    //	int cur=clock();
    	read(n),read(m),p=sqrt(N)+1;
    	for(int i=1;i<N;++i)	bl[i]=(i-1)/p+1;
    	for(int i=1;i<=n;++i)	read(a[i]);
    	for(int i=1;i<=bl[n];++i)
    		L[i]=(i-1)*p+1,R[i]=i*p;R[bl[n]]=n;
    	for(int x=1;x<=bl[n];++x)	build(x);
    	for(int x=1;x<=bl[n];++x) {
    		for(int i=1;i<N;++i)	s2[x][i]=s2[x-1][i];
    		for(int i=1;i<=bl[N-1];++i)	s1[x][i]=s1[x-1][i];
    		for(int i=L[x];i<=R[x];++i)	++s1[x][bl[a[i]]],++s2[x][a[i]];
    	}
    	for(;m;--m) {
    		int opt,x,y;read(opt),read(x),read(y);
    		if(opt==1) { int z,w;read(z),read(w),modify(x,y,z,w); }
    		else { int k;read(k),print(ask(x,y,k)); }
    	}
    	pr[--lp]=''; puts(pr);
    //	printf(">>> %d ms.
    ",clock()-cur);
    	return 0;
    }
    
  • 相关阅读:
    ZOJ 1002 Fire Net (火力网)
    UVa OJ 117 The Postal Worker Rings Once (让邮差只走一圈)
    UVa OJ 118 Mutant Flatworld Explorers (变体扁平世界探索器)
    UVa OJ 103 Stacking Boxes (嵌套盒子)
    UVa OJ 110 MetaLoopless Sorts (无循环元排序)
    第一次遇到使用NSNull的场景
    NSURL使用浅析
    从CNTV下载《小小智慧树》
    NSDictionary and NSMutableDictionary
    Category in static library
  • 原文地址:https://www.cnblogs.com/daniel14311531/p/10197853.html
Copyright © 2011-2022 走看看