• BZOJ 2653: middle(主席树+二分答案)


    传送门

    解题思路

      首先可以想到一种暴力做法,就是询问时二分,然后大于等于这个值的设为1,否则设为-1,然后就和GSS1那样统计答案。但是发现这样时间空间复杂度都很爆炸,所以考虑预处理,可以用主席树来做了。以(rt[i])为根线段树维护二分的答案为(i)的线段树,线段树下标是位置。处理的时候就排一遍序,然后每次(mid+1)的时候发现只有(mid)这个位置的值要变成(-1),所以可以直接处理。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    
    using namespace std;
    const int N=20005;
    const int M=N*20;
    
    template<class T> void rd(T &x){
    	x=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    }
    inline int qmax(int x,int y){return x>y?x:y;}
    
    int n,m,a[N],id[N],lx[M],rx[M],sum[M],ls[M],rs[M],tot,rt[N];
    int q[10];
    
    inline bool cmp(int x,int y){return a[x]<a[y];}
    
    void build(int &x,int l,int r){
    	x=++tot;int mid=(l+r)>>1;
    	if(l==r) {sum[x]=lx[x]=rx[x]=1;return ;}
    	build(ls[x],l,mid);build(rs[x],mid+1,r);
    	sum[x]=sum[ls[x]]+sum[rs[x]];
    	lx[x]=rx[x]=sum[x];
    }
    
    void update(int pre,int &x,int l,int r,int k){
    	x=++tot;sum[x]=sum[pre];rx[x]=rx[pre];
    	ls[x]=ls[pre];rs[x]=rs[pre];lx[x]=lx[pre];	
    	if(l==r) {lx[x]=rx[x]=sum[x]=-1;return ;}
    	int mid=(l+r)>>1;
    	if(k<=mid) update(ls[pre],ls[x],l,mid,k);
    	else update(rs[pre],rs[x],mid+1,r,k);
    	sum[x]=sum[ls[x]]+sum[rs[x]];
    	lx[x]=qmax(lx[ls[x]],sum[ls[x]]+lx[rs[x]]);
    	rx[x]=qmax(rx[rs[x]],sum[rs[x]]+rx[ls[x]]);
    }
    
    int query_sum(int x,int l,int r,int L,int R){
    	if(L>R) return 0;
    	if(L<=l && r<=R) return sum[x];
    	int mid=(l+r)>>1,ret=0;
    	if(L<=mid) ret+=query_sum(ls[x],l,mid,L,R);
    	if(mid<R) ret+=query_sum(rs[x],mid+1,r,L,R);
    	return ret;
    }
    
    int query_lx(int x,int l,int r,int L,int R){
    	if(L<=l && r<=R) return lx[x];
    	int mid=(l+r)>>1;
    	if(L>mid) return query_lx(rs[x],mid+1,r,L,R);
    	else if(mid>=R) return query_lx(ls[x],l,mid,L,R);
    	else return qmax(query_lx(ls[x],l,mid,L,R),query_sum(ls[x],l,mid,L,R)+query_lx(rs[x],mid+1,r,L,R));
    }
    
    int query_rx(int x,int l,int r,int L,int R){
    	if(L<=l && r<=R) return rx[x];
    	int mid=(l+r)>>1;
    	if(L>mid) return query_rx(rs[x],mid+1,r,L,R);
    	else if(mid>=R) return query_rx(ls[x],l,mid,L,R);
    	else return qmax(query_rx(rs[x],mid+1,r,L,R),query_sum(rs[x],mid+1,r,L,R)+query_rx(ls[x],l,mid,L,R));
    }
    
    inline bool check(int lim){
    	int ret=0;
    	ret+=query_sum(rt[lim],1,n,q[2]+1,q[3]-1);
    	ret+=query_lx(rt[lim],1,n,q[3],q[4]);
    	ret+=query_rx(rt[lim],1,n,q[1],q[2]);
    	return ret>=0?1:0;
    }
    
    int main(){
    	rd(n);int lstans=0;
    	for(int i=1;i<=n;i++) rd(a[i]),id[i]=i;
    	sort(id+1,id+1+n,cmp);build(rt[1],1,n);sort(a+1,a+1+n);
    	for(int i=2;i<=n+1;i++) update(rt[i-1],rt[i],1,n,id[i-1]);
    	for(rd(m);m;m--){
    		rd(q[1]);rd(q[2]);rd(q[3]);rd(q[4]);
    		q[1]=(q[1]+lstans)%n+1;q[2]=(q[2]+lstans)%n+1;
    		q[3]=(q[3]+lstans)%n+1;q[4]=(q[4]+lstans)%n+1;
    		sort(q+1,q+1+4);int L=1,R=n,mid;
    		while(L<=R){
    			mid=(L+R)>>1;
    			if(check(mid)) lstans=mid,L=mid+1;
    			else R=mid-1;
    		}
    		printf("%d
    ",a[lstans]);lstans=a[lstans];
    	}
    	return 0;
    }
    
  • 相关阅读:
    文件上传长度限制
    js之图片放大
    Jquery中$与$.fn的区别
    取消svn和文件的关联
    Java——如何创建文件夹及文件,删除文件,文件夹
    SQL语法
    linux环境运行java项目并有外部引用jar
    Eclipse-与Centos远程调试
    Eclipse-远程调试
    使用java代码执行linux命令
  • 原文地址:https://www.cnblogs.com/sdfzsyq/p/10253506.html
Copyright © 2020-2023  润新知