zoukankan      html  css  js  c++  java
  • BZOJ 2653: middle

    2653: middle

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1536  Solved: 855
    [Submit][Status][Discuss]

    Description

      一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整。
      给你一个长度为n的序列s。
      回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。
      其中a<b<c<d。
      位置也从0开始标号。
      我会使用一些方式强制你在线。

    Input

      第一行序列长度n。
      接下来n行按顺序给出a中的数。
      接下来一行Q。
      然后Q行每行a,b,c,d,我们令上个询问的答案是x(如果这是第一个询问则x=0)。
      令数组q={(a+x)%n,(b+x)%n,(c+x)%n,(d+x)%n}。
      将q从小到大排序之后,令真正的要询问的a=q[0],b=q[1],c=q[2],d=q[3]。
      输入保证满足条件。

    Output

      Q行依次给出询问的答案。

    Sample Input

    5
    170337785
    271451044
    22430280
    969056313
    206452321
    3
    3 1 0 2
    2 3 1 4
    3 1 4 0

    271451044
    271451044
    969056313

    Sample Output

     

    HINT

      0:n,Q<=100

      1,...,5:n<=2000

      0,...,19:n<=20000,Q<=25000


    Source

    分析:

    首先我们大概都能够想到二分答案然后判断...

    怎么判断?一个很经典的思想,我才不会告诉你我没有想到QAQ...

    对于一个序列S,设其中位数位M,二分答案位ans,如果M>=ans,那么一定满足S中有大于等于$frac{|S|}{2}$的数字大于等于ans,所以我们需要在给顶序列中寻找合法的子序列使得存在M>=ans,我们可以把大于等于ans的数字置成1,小于ans的数字置为0,然后问题就转化为了在合法序列中寻找最大子段和使得其大于等于0...这就是基础的线段树问题,但是这样我们就需要n个线段树,很显然这是不兹磁的...所以我们先把ans=1(离散化之后)的线段树建出来,也就是说每个位置都是1,然后对于以后的i,用可持久化线段树单点修改压空间...查询的时候就在对应的线段树上查询即可...

    代码:

    不要问我为什么我要手写lower_bound还写得这么鬼畜...因为我开心...调都没调就A了...

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    //by NeighThorn
    using namespace std;
    
    const int maxn=20000+5,maxm=7000000+5;
    
    int n,q,len,tot,ls[maxm],rs[maxm],sum[maxm],lmax[maxm],rmax[maxm],root[maxn];
    
    long long a[maxn],mp[maxn];
    
    vector<int> M[maxn];
    
    inline int find(long long _){
    	int __=1,___=len,____;
    	while(__<=___){
    		int _____=(__+___)>>1;
    		if(mp[_____]>=_)
    			____=_____,___=_____-1;
    		else
    			__=_____+1;
    	}
    	return ____;
    }
    
    inline void build(int l,int r,int &x){
    	x=++tot;
    	if(l==r){
    		lmax[x]=rmax[x]=sum[x]=1;
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(l,mid,ls[x]),build(mid+1,r,rs[x]);
    	sum[x]=sum[ls[x]]+sum[rs[x]];
    	lmax[x]=max(lmax[ls[x]],sum[ls[x]]+lmax[rs[x]]);
    	rmax[x]=max(rmax[rs[x]],sum[rs[x]]+rmax[ls[x]]);
    }
    
    inline void change(int l,int r,int x,int &y,int pos,int val){
    	y=++tot;
    	if(l==r){
    		lmax[y]=rmax[y]=sum[y]=val;
    		return;
    	}
    	int mid=(l+r)>>1;ls[y]=ls[x],rs[y]=rs[x];
    	if(pos<=mid)
    		change(l,mid,ls[x],ls[y],pos,val);
    	else
    		change(mid+1,r,rs[x],rs[y],pos,val);
    	sum[y]=sum[ls[y]]+sum[rs[y]];
    	lmax[y]=max(lmax[ls[y]],sum[ls[y]]+lmax[rs[y]]);
    	rmax[y]=max(rmax[rs[y]],sum[rs[y]]+rmax[ls[y]]);
    }
    
    inline int querysum(int l,int r,int L,int R,int x){
    	if(l==L&&r==R)
    		return sum[x];
    	int mid=(l+r)>>1;
    	if(R<=mid)
    		return querysum(l,mid,L,R,ls[x]);
    	else if(L>mid)
    		return querysum(mid+1,r,L,R,rs[x]);
    	else
    		return querysum(l,mid,L,mid,ls[x])+querysum(mid+1,r,mid+1,R,rs[x]);
    }
    
    inline int queryrmax(int l,int r,int L,int R,int x){
    	if(l==L&&r==R)
    		return rmax[x];
    	int mid=(l+r)>>1;
    	if(R<=mid)
    		return queryrmax(l,mid,L,R,ls[x]);
    	else if(L>mid)
    		return queryrmax(mid+1,r,L,R,rs[x]);
    	else
    		return max(queryrmax(l,mid,L,mid,ls[x])+querysum(mid+1,r,mid+1,R,rs[x]),queryrmax(mid+1,r,mid+1,R,rs[x]));
    }
    
    inline int querylmax(int l,int r,int L,int R,int x){
    	if(l==L&&r==R)
    		return lmax[x];
    	int mid=(l+r)>>1,ans;
    	if(R<=mid)
    		return querylmax(l,mid,L,R,ls[x]);
    	else if(L>mid)
    		return querylmax(mid+1,r,L,R,rs[x]);
    	else
    		return max(querylmax(mid+1,r,mid+1,R,rs[x])+querysum(l,mid,L,mid,ls[x]),querylmax(l,mid,L,mid,ls[x]));
    }
    
    signed main(void){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%lld",&a[i]),mp[i]=a[i];
    	sort(mp+1,mp+n+1),len=unique(mp+1,mp+n+1)-mp-1;
    	for(int i=1;i<=n;i++)
    		a[i]=find(a[i]),M[a[i]].push_back(i);
    	build(1,n,root[1]);
    	for(int i=2;i<=len;i++)
    		if(M[i-1].size()>0){
    			change(1,n,root[i-1],root[i],M[i-1][0],-1);
    			for(int j=0;j<M[i-1].size();j++)
    				change(1,n,root[i],root[i],M[i-1][j],-1);
    		}
    	scanf("%d",&q);long long ans=0,a[4];
    	for(int i=1;i<=q;i++){
    		for(int j=0;j<4;j++)
    			scanf("%lld",&a[j]),a[j]=(a[j]+ans)%n,a[j]++;
    		sort(a,a+4);
    		int l=1,r=len;
    		while(l<=r){
    			int mid=(l+r)>>1;
    			int lm=queryrmax(1,n,a[0],a[1],root[mid]);
    			int s=0;
    			if(a[1]+1<=a[2]-1)
    				s=querysum(1,n,a[1]+1,a[2]-1,root[mid]);
    			int rm=querylmax(1,n,a[2],a[3],root[mid]);
    			if(lm+s+rm>=0)
    				ans=mid,l=mid+1;
    			else
    				r=mid-1;
    		}ans=mp[ans];
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    短文本理解蓝图
    BERT在工业界落地的常用三步
    C#:面试相关问题集
    Delphi线程简介Create及其参数、Resume、Suspend和Terminate(转载)
    迭代器模式(学习笔记19)
    备忘录模式(学习笔记21)
    GPS中地面航向角,磁偏角
    访问者模式(学习笔记20)
    easyui:初始化失败的问题
    访问者模式(学习笔记22)
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6399126.html
Copyright © 2011-2022 走看看