zoukankan      html  css  js  c++  java
  • [BZOJ 2653] middle

    [BZOJ 2653] middle

    题意

    一个长度为 (n) 的序列 (a) , 设其升序排序之后为 (b) , 其中位数定义为 (b[n/2]), 其中 (a,b)(0) 开始标号,除法取下整.

    给你一个长度为 (n) 的序列 (s). 回答 (q) 个这样的询问: (s) 的左端点在 ([a,b]) 之间,右端点在 ([c,d]) 之间的子序列中, 最大的中位数. 其中 (a<b<c<d). 位置也从 (0) 开始标号.

    (nle 2 imes 10^4,qle2.5 imes 10^4).

    强制在线.

    题解

    题里面最坑人的大概就是那个下取整又从 (0) 开始标号了...相当于取第 (left lfloor frac n 2 ight floor+1) 个值. 也就是说偶数的情况下取靠后的那个值作为中位数.

    顺便在这题里了解了一些中位数处理的操作.

    首先对于一个查询我们二分一个答案 (k), 问题转化为能否有一个合乎询问的区间中位数不小于 (k). 我们如果把原数列中满足 (xge k) 的看作 (+1), (x<k) 的看作 (-1), 那么只要有一个区间的和非负就可以满足条件.

    那么我们可以用线段树来维护一下区间和以及最大前后缀和. ([b,c]) 部分是必然要选的, 再加上 ([a,b-1]) 的最大后缀和以及 ([c+1,d]) 的最大前缀和即可.

    至于这些线段树, 我们可以发现相邻的值对应的线段树差别不大, 只差了值相等的几个地方. 所以我们可以可持久化一下解决.

    代码不难写.

    参考代码

    #include <bits/stdc++.h>
    
    const int MAXN=20010;
    
    struct Node{
    	struct Data{
    		int sum;
    		int lsum;
    		int rsum;
    		Data(){}
    		Data(int a,int b,int c):sum(a),lsum(b),rsum(c){}
    		Data friend operator+(const Data& a,const Data& b){
    			return Data(
    				a.sum+b.sum,
    				std::max(a.lsum,a.sum+b.lsum),
    				std::max(b.rsum,a.rsum+b.sum)
    			);
    		}
    	};
    	int l;
    	int r;
    	Data v;
    	Node* lch;
    	Node* rch;
    	Node(Node*);
    	void Print();
    	Node(int,int);
    	void Negate(int);
    	Data Query(int,int);
    };
    Node* N[MAXN];
    
    int n;
    int q;
    int cnt;
    int a[MAXN];
    int s[MAXN];
    std::vector<int> pos[MAXN];
    
    int main(){
    	scanf("%d",&n);
    	for(int i=0;i<n;i++){
    		scanf("%d",a+i);
    		s[i]=a[i];
    	}
    	std::sort(s+1,s+n+1);
    	cnt=std::unique(s+1,s+n+1)-(s+1);
    	for(int i=0;i<n;i++){
    		a[i]=std::lower_bound(s+1,s+cnt+1,a[i])-s;
    		pos[a[i]].push_back(i);
    	}
    	N[1]=new Node(0,n-1);
    	for(int i=1;i<cnt;i++){
    		N[i+1]=new Node(N[i]);
    		for(auto p:pos[i])
    			N[i+1]->Negate(p);
    	}
    	scanf("%d",&q);
    	int lastans=0;
    	for(int i=0;i<q;i++){
    		int q[4];
    		for(int i=0;i<4;i++){
    			scanf("%d",q+i);
    			(q[i]+=lastans)%=n;
    		}
    		std::sort(q,q+4);
    		int l=1,r=cnt+1;
    		while(r-l>1){
    			int mid=(l+r)>>1;
    			int sum=0;
    			if(q[2]-q[1]>1)
    				sum+=N[mid]->Query(q[1]+1,q[2]-1).sum;
    			sum+=N[mid]->Query(q[0],q[1]).rsum+N[mid]->Query(q[2],q[3]).lsum;
    			if(sum>=0)
    				l=mid;
    			else
    				r=mid;
    		}
    		printf("%d
    ",lastans=s[l]);
    	}
    	return 0;
    }
    
    Node::Node(Node* p){
    	*this=*p;
    }
    
    Node::Data Node::Query(int l,int r){
    	if(l<=this->l&&this->r<=r)
    		return this->v;
    	else{
    		if(r<=this->lch->r)
    			return this->lch->Query(l,r);
    		if(this->rch->l<=l)
    			return this->rch->Query(l,r);
    		return this->lch->Query(l,r)+this->rch->Query(l,r);
    	}
    }
    
    void Node::Negate(int x){
    	if(this->l==this->r)
    		this->v=Data(-1,-1,-1);
    	else{
    		if(x<=this->lch->r){
    			this->lch=new Node(this->lch);
    			this->lch->Negate(x);
    		}
    		else{
    			this->rch=new Node(this->rch);
    			this->rch->Negate(x);
    		}
    		this->v=this->lch->v+this->rch->v;
    	}
    }
    
    void Node::Print(){
    	if(this==NULL)
    		return;
    	printf("[%d,%d] {sum=%d,lsum=%d,rsum=%d}
    ",l,r,v.sum,v.lsum,v.rsum);
    	this->lch->Print();
    	this->rch->Print();
    }
    
    Node::Node(int l,int r):l(l),r(r){
    	if(l==r)
    		this->v=Data(1,1,1);
    	else{
    		int mid=(l+r)>>1;
    		this->lch=new Node(l,mid);
    		this->rch=new Node(mid+1,r);
    		this->v=this->lch->v+this->rch->v;
    	}
    }
    

  • 相关阅读:
    系统剪切板的使用UIPasteboard
    iOS开发之GCD总结
    OC报错,after command failed: Directory not empty
    一个女孩被车多次撞到的经历
    iOS一个很好的内存检测工具
    iOS 数据库sqlite3.0操作--超简单--看我就够啦
    推送碰到的一个坑
    iOS之3DTouch的使用---很简单,看我就够啦~~
    简谈造成循环引用的原因以及处理办法
    关于拼过消息推送回调,然后跳转到指定界面
  • 原文地址:https://www.cnblogs.com/rvalue/p/10427676.html
Copyright © 2011-2022 走看看