zoukankan      html  css  js  c++  java
  • P2839 [国家集训队]middle

    LuoP2839 [国家集训队]middle

    主席树好题,点个赞!
    这道题让我知道了,主席树不只是维护权值线段树。也是可以去像普通线段树一样操作的.
    首先,关于求区间中位数的一个小(trick)(反正我之前没听说过)
    二分答案
    将大于等于(mid)的值看做(1),小于(mid)的看做(-1)
    那么如果区间和大于等于(0),则说明区间中位数大于等于(mid)(因为此题定义偶数个元素时,中位数为中间靠前的一个,如果是靠后的就要严格大于了)
    之后,发现这个左端点和右端点不固定有点恶心.但是([b + 1,c - 1])是一定要选的,所以([b + 1,c - 1])这个区间和的贡献是要算的
    所以我们先算这一区间的值。然后区间([a,b]),([c,d]).我们最优选,就是最大前缀后缀和啊
    所以要维护区间和,最大左起子段和,最大右起子段和

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<cctype>
    #define LL long long
    const int N = 2e4 + 3;
    struct node{
    	int sum;
    	int lsum,rsum;
    	int lc,rc;
    }a[N << 6];
    struct inf{
    	LL val;
    	int pos;	
    }v[N];
    int rt[N];
    int n,q,t;
    inline LL read(){
    	LL v = 0,c = 1;char ch = getchar();
    	while(!isdigit(ch)){
    		if(ch == '-') c = -1;
    		ch = getchar();	
    	}
    	while(isdigit(ch)){
    		v = v * 10 + ch - 48;
    		ch = getchar();	
    	}
    	return v * c;	
    }
    inline void pushup(int u){
    	a[u].sum = a[a[u].lc].sum + a[a[u].rc].sum;
    	a[u].lsum = std::max(a[a[u].lc].lsum,a[a[u].lc].sum + a[a[u].rc].lsum);
    	a[u].rsum = std::max(a[a[u].rc].rsum,a[a[u].rc].sum + a[a[u].lc].rsum);
    }
    inline void build(int &u,int l,int r){
    	u = ++t;
    	if(l == r){
    		a[u].sum = a[u].lsum = a[u].rsum = 1;
    		return ;	
    	}
    	int mid = (l + r) >> 1;
    	build(a[u].lc,l,mid);
    	build(a[u].rc,mid + 1,r);
    	pushup(u);
    }
    inline void ins(int &u,int l,int r,int x){
    	a[++t] = a[u];	
    	u = t;
    	if(l == r){
    		a[u].sum = -1;
    		a[u].lsum = -1;
    		a[u].rsum = -1;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid) ins(a[u].lc,l,mid,x);
    	else ins(a[u].rc,mid + 1,r,x);
    	pushup(u);
    }
    inline int query_sum(int u,int l,int r,int ll,int rr){
    	if(rr < ll) return 0;
    	if(l == ll && r == rr) return a[u].sum;
    	int mid = (l + r) >> 1;
    	if(rr <= mid) return query_sum(a[u].lc,l,mid,ll,rr);
    	else if(ll > mid) return query_sum(a[u].rc,mid + 1,r,ll,rr);
    	else return query_sum(a[u].lc,l,mid,ll,mid) + query_sum(a[u].rc,mid + 1,r,mid + 1,rr);	
    }
    inline int query_lsum(int u,int l,int r,int ll,int rr){
    	if(rr < ll) return 0;
    	if(l == ll && r == rr) return a[u].lsum;
    	int mid = (l + r) >> 1;
    	if(rr <= mid) return query_lsum(a[u].lc,l,mid,ll,rr);
    	else if(ll > mid) return query_lsum(a[u].rc,mid + 1,r,ll,rr);
    	else return std::max(query_lsum(a[u].lc,l,mid,ll,mid),query_sum(a[u].lc,l,mid,ll,mid) 
    	+ query_lsum(a[u].rc,mid + 1,r,mid + 1,rr));
    }
    inline int query_rsum(int u,int l,int r,int ll,int rr){
    	if(rr < ll) return 0;
    	if(l == ll && r == rr) return a[u].rsum;
    	int mid = (l + r) >> 1;
    	if(rr <= mid) return query_rsum(a[u].lc,l,mid,ll,rr);
    	else if(ll > mid) return query_rsum(a[u].rc,mid + 1,r,ll,rr);
    	else return std::max(query_rsum(a[u].rc,mid + 1,r,mid + 1,rr),query_sum(a[u].rc,mid + 1,r,mid + 1,rr) + 
    	query_rsum(a[u].lc,l,mid,ll,mid));	
    }
    inline bool check(int mid,int Q1,int Q2,int Q3,int Q4){
    	int res = 0;
    	//printf("%d %d %d %d
    ",Q1,Q2,Q3,Q4);
    	res += query_sum(rt[mid],1,n,Q2 + 1,Q3 - 1);
    	res += query_rsum(rt[mid],1,n,Q1,Q2);
    	res += query_lsum(rt[mid],1,n,Q3,Q4);
    	return res >= 0;
    }
    inline bool cmp(inf x,inf y){
    	return x.val < y.val;
    }
    int main(){
    	n = read();
    	for(int i = 1;i <= n;++i){
    		v[i].val = read();
    		v[i].pos = i;	
    	}
    	std::sort(v + 1,v + n + 1,cmp);
    	build(rt[1],1,n);
    	for(int i = 2;i <= n + 1;++i) {
    		rt[i] = rt[i - 1];
    		ins(rt[i],1,n,v[i - 1].pos);
    	}
    	q = read();
    	LL last = 0,Q[4];
    	while(q--){
    		for(int i = 0;i < 4;++i) Q[i] = (read() + last ) % n + 1;
    		std::sort(Q,Q + 4);
    		int l = 1,r = n,ans;
    		while(l <= r){
    			int mid = (l + r) >> 1;//printf("%d
    ",mid);
    			if(check(mid,Q[0],Q[1],Q[2],Q[3])) ans = mid,l = mid + 1;
    			else r = mid - 1;	
    		}
    		printf("%lld
    ",last = v[ans].val);
    	}
    	return 0;	
    }
    
  • 相关阅读:
    超赞!不容错过的5款实用网页开发和设计工具
    如何从平面设计转行到UI设计?
    线段树
    RMQ
    Splay
    Treap
    *模板--矩阵
    最小生成树
    hash
    ac自动机
  • 原文地址:https://www.cnblogs.com/wyxdrqc/p/10644720.html
Copyright © 2011-2022 走看看