• 【BZOJ2653】【洛谷2839】—Middle(主席树+二分答案)


    BZOJ传送门

    洛谷

    这种题为什么会在我谷上黑题啊?有毒吧

    想起一道相似的题【HEOI2016/TJOI2016】排序

    而这道题是要求最大中位数

    我们考虑二分一个数midmid

    将所有小于midmid的赋为1-1,其余赋为11

    那也就是说如果我们能在aa~bb, cc~dd之间选一段区间使其和sum>=0sum>=0

    那么我们的下界显然就可以调高

    那问题就变成了怎么求这一段的最大子段和

    考虑到bb+11~cc-11之间是必须要的选的

    aa~bb选靠右的最大子段, cc~dd选靠左的最大子段

    用线段树维护一下区间和,区间最大左段、右段和就可以了

    那么现在剩下的问题就是怎么构建线段树

    如果每次询问都构建的话显然复杂度是O(n2logn)O(n^2logn)

    我们考虑到如果midmid从小到大,显然线段树中是单调的不断有点从11变成1-1

    那显然一共只有nn种可能的线段树,而且它们相互只有一个节点不一样

    那改成主席树就可以了

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
    	char ch=getchar();
    	int res=0,f=1;
    	while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
    	while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    	return res*f;
    }
    const int N=20005;
    struct Seg{
    	int sum,l,r,lson,rson;
    	Seg(int a=0):sum(a),l(a),r(a),lson(a),rson(a){}
    	friend inline Seg operator +(const Seg&a,const Seg&b){
    		Seg res;res.sum=a.sum+b.sum;
    		res.l=max(a.l,a.sum+b.l),res.r=max(b.r,a.r+b.sum);
    		return res;
    	}
    }tr[N<<2];
    struct pc{
    	int val,pos;
    }a[N];
    inline bool comp(const pc&a,const pc&b){
    	return a.val<b.val;
    }
    int rt[N],q[5],ans,n,m,tot;
    #define lc tr[u].lson
    #define rc tr[u].rson
    #define mid ((l+r)>>1)
    inline void pushup(int u){
    	tr[u].sum=tr[lc].sum+tr[rc].sum;
    	tr[u].l=max(tr[lc].l,tr[lc].sum+tr[rc].l);
    	tr[u].r=max(tr[rc].r,tr[lc].r+tr[rc].sum);
    }
    void buildtree(int &u,int l,int r){
    	u=++tot;
    	if(l==r){tr[u].sum=tr[u].l=tr[u].r=1;return;}
    	buildtree(lc,l,mid);
    	buildtree(rc,mid+1,r);
    	pushup(u);
    }
    void update(int &u,int r1,int l,int r,int p){
    	u=++tot,tr[u]=tr[r1];
    	if(l==r){tr[u].sum=tr[u].l=tr[u].r=-1;return;}
    	if(p<=mid)update(lc,tr[r1].lson,l,mid,p);
    	else update(rc,tr[r1].rson,mid+1,r,p);
    	pushup(u);
    }
    Seg query(int u,int l,int r,int st,int des){
    	if(st<=l&&r<=des)return tr[u];
    	if(des<=mid)return query(lc,l,mid,st,des);
    	if(mid<st)return query(rc,mid+1,r,st,des);
    	return query(lc,l,mid,st,des)+query(rc,mid+1,r,st,des);
    }
    inline bool check(int k,int a,int b,int c,int d){
    	int res=0;
    	if(b+1<=c-1)res+=query(rt[k],0,n-1,b+1,c-1).sum;
    	res+=query(rt[k],0,n-1,a,b).r;
    	res+=query(rt[k],0,n-1,c,d).l;
    	return res>=0;
    }
    #undef mid
    signed main(){
    	n=read();
    	for(int i=0;i<n;i++)a[i].val=read(),a[i].pos=i;
    	sort(a,a+n,comp);								
    	buildtree(rt[0],0,n-1);
    	for(int i=1;i<n;i++)update(rt[i],rt[i-1],0,n-1,a[i-1].pos);
    	m=read();
    	for(int i=1;i<=m;i++){
    		q[1]=(read()+ans)%n,q[2]=(read()+ans)%n,q[3]=(read()+ans)%n,q[4]=(read()+ans)%n;
    		sort(q+1,q+5);
    		int l=0,r=n-1,p=0;
    		while(l<=r){
    			int mid=(l+r)>>1;
    			if(check(mid,q[1],q[2],q[3],q[4]))l=mid+1,p=mid;
    			else r=mid-1;
    		}
    		cout<<(ans=a[p].val)<<'
    ';
    	}
    }
    
  • 相关阅读:
    Nginx常用日志分割方法
    nginx的 CPU参数worker_processes和worker_cpu_affinity使用说明
    js中的“==”和“===”的区别
    学习JS
    svg
    用户界面设计
    bootstrap和easyui
    axure—日期函数
    axure--轮播图
    字符串属性和函数的使用
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/10366338.html
Copyright © 2020-2023  润新知