zoukankan      html  css  js  c++  java
  • 蒲公英(bzoj2724)(分块+区间众数)

    Input

    Output

    Sample Input

    6 3 
    1 2 3 2 1 2 
    1 5 
    3 6 
    1 5
    

    Sample Output

    1 
    2 
    1 
    

    HINT

    (n <= 40000),$ m <= 50000$

    题意:

    求区间众数

    题解:

    见代码

    //解决本题的重要性质: 
    //对于两个区间a,b,其中已知a区间的众数k 
    //则众数一定为k或是b区间的任意一个数  
    #include<bits/stdc++.h>
    #define re register int 
    using namespace std;
    const int N=40010,M=410;
    int n,q,m,blen,bsum;
    int a[N],b[N];//b为离散数组 
    int bl[M][M];//bl[i][j]表示第i个块中的第j个数,bl[i][0]表示第i个块的长度 
    int bk[N];//bk[i]表示第i个数(在原数列中)在第bk[i]个块中 
    int f[M][M];//f[i][j]表示第i块到第j块之间的众数 
    int g[N][M];//g[i][j]表示i在前j个块中出现的次数 
    void init(){//初始化 
    	for(int i=1,j=1;i<=n;++j){
    		int k;
    		for(k=1;k<=blen&&i<=n;++i,++k){
    			bk[i]=j;
    			bl[j][k]=a[i];
    		}k--;
    		bl[j][0]=k;
    		bsum=j;
    	}//处理块 
    	for(int i=1;i<=bsum;++i){
    		for(int j=1;j<=m;++j){
    			g[j][i]=g[j][i-1];
    		}
    		for(int j=1;j<=bl[i][0];++j){
    			g[bl[i][j]][i]++;
    		}
    	}//预处理g数组 
    	for(int i=1;i<=bsum;++i){
    		for(int j=i;j<=bsum;++j){
    			int num=f[i][j-1];int mx=g[num][j]-g[num][i-1];
    			for(int k=1;k<=bl[j][0];++k){
    				int now=g[bl[j][k]][j]-g[bl[j][k]][i-1];
    				if(now>mx||(now==mx&&bl[j][k]<num))num=bl[j][k],mx=now;
    			}
    			f[i][j]=f[j][i]=num;
    		}
    	}//预处理f数组 
    }
    void read(){//读入 
    	cin>>n>>q;blen=sqrt(n);
    	for(int i=1;i<=n;++i)scanf("%d",a+i),b[i]=a[i];
    }
    void lsh(){
    	sort(b+1,b+n+1);
    	m=unique(b+1,b+n+1)-b-1;
    	for(int i=1;i<=n;++i)a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    }
    void work(){
    	int last=0;
    	while(q--){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		l=(l+last-1)%n+1;
    		r=(r+last-1)%n+1;
    		if(l>r)swap(l,r);
    		static int bj[M],cnt,v[N];cnt=0;//bj记录边角的数据,cnt为边角数据的数量
    		int L,R,num,mx; 
    		if(bk[l]==bk[r]){//在同一块内暴力求众数 
    			for(int i=l;i<=r;++i)bj[++cnt]=a[i],v[a[i]]++;
    			mx=0;
    			for(int i=l;i<=r;++i){
    				if(v[a[i]]>mx||(v[a[i]]==mx&&a[i]<num))num=a[i],mx=v[a[i]];
    			}
    			printf("%d
    ",last=b[num]);
    		}else{//在不同块时,将中间当成一大块和边角比较
    		      //根据性质,众数只有可能是中间这一块的众数或是边角上的数
    			  //所以暴力枚举再判断就行了 
    			re i;
    			for(i=l;bk[i]==bk[i-1];++i){
    				bj[++cnt]=a[i];v[a[i]]++;
    			}L=bk[i]; 
    			for(i=r;bk[i]==bk[i+1];--i){
    				bj[++cnt]=a[i];v[a[i]]++;
    			}R=bk[i];
    		    num=f[L][R],mx=v[num]+g[num][R]-g[num][L-1];
    		    for(i=1;i<=cnt;++i){
    		    	int now=v[bj[i]]+g[bj[i]][R]-g[bj[i]][L-1];
    		    	if(now>mx||(now==mx&&bj[i]<num))num=bj[i],mx=now;
    			}
    			printf("%d
    ",last=b[num]);
    		}
    		for(re i=1;i<=cnt;++i)--v[bj[i]];//v数组要这样清空,复杂度O(cnt),不能用memset,那样是O(n)
    	}
    }
    int main(){
    	read();
    	lsh();
    	init();
    	work(); 
    }
    
  • 相关阅读:
    [转]采样和滤波
    "我的电脑"和所有文件夹打不开的解决办法
    巨无霸“火星”CPU散热器亮相
    [转]规范化编程:ANSI和UNICODE的使用
    2006第三季度:10大最糟科技事件
    【掉下巴】如此公路
    Windows CE 初体验 幻灯
    Windows CE.NET Core OS 特性详解(二)最终用户应用程序
    基于PB的Windows CE模拟环境的配置及调试
    非阻塞I/O
  • 原文地址:https://www.cnblogs.com/zhenglier/p/10100608.html
Copyright © 2011-2022 走看看