• BZOJ2653 middle 中位数套路 可持久化线段树优化


    BZOJ2653 middle 中位数套路 可持久化线段树优化

    题意

    给定长度为(n)的序列,给定(q)个询问,每个询问将给定区间([a,b]),([c,d]),要求左端点和右端点分别位于两个区间中,求区间的最大中位数能取多少,强制在线

    [n leq 2e4\ q leq 2500 ]

    分析

    对于中位数通常可以二分答案,然后将原序列大于等于该数的记作(1),小于该数的记作(-1),如果和大于等于(0),说明中位数可以变大

    此题区间端点可以任意选择,但是中间([b + 1,c - 1])必须选定,因此一定选择([a,b])的最大后缀和和([c,d])的最大前缀和累计

    因此不妨对每个数建立线段树,维护区间最大前缀,后缀,区间和。对于每个二分的数考察其线段树,可以可持久化的原因是每次增加一个数最多需要更改一个位置,空间足够。

    感觉是一种比较巧妙的建树思想

    代码

    #include<bits/stdc++.h>
    #define re register
    #define pii pair<int,int>
    #define fi first
    #define se second 
    using namespace std;
    typedef long long ll;
    
    const int maxn = 2e4 + 5;
    
    ll rd(){
    	ll x = 0;
    	int f = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') {
    		if(ch == '-') f = -1;
    		ch = getchar();
    	} 
    	while(ch >= '0' && ch <= '9') {
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    	return x * f;
    }
    
    
    struct info{
    	int tot,lmax,rmax;
    	inline info operator + (const info &a) {
    		return (info){
    			tot + a.tot,
    			max(lmax,tot + a.lmax),
    			max(a.rmax,a.tot + rmax)
    		};
    	}
    	inline void init(int _tot,int _l,int _r){
    		tot = _tot;
    		lmax = _l;
    		rmax = _r;
    	}
    };
    
    struct Node{
    	int ls,rs;
    	info sum;
    }node[maxn * 40 + 5];
    
    int rt[maxn];
    pii a[maxn];
    int n;
    
    struct PST{
    	int tt;
    	inline void push_up(int i){
    		node[i].sum = node[node[i].ls].sum + node[node[i].rs].sum;
    	}
    	void build(int &rt,int l,int r){
    		int tmp = rt;
    		rt = ++tt;
    		node[rt] = node[tmp];
    		if(l == r) {
    			node[rt].sum.init(1,1,1);
    			return;
    		}
    		int mid = l + r >> 1;
    		build(node[rt].ls,l,mid);
    		build(node[rt].rs,mid + 1,r);
    		push_up(rt);
    	}
    	void update(int &rt,int l,int r,int v){
    		int tmp = rt;
    		rt = ++tt;
    		node[rt] = node[tmp];
    		if(l == r) {
    			node[rt].sum.init(-1,-1,-1);
    			return;
    		}
    		int mid = l + r >> 1;
    		if(v <= mid) update(node[rt].ls,l,mid,v);
    		else update(node[rt].rs,mid + 1,r,v);
    		push_up(rt);
    	}
    	info query(int i,int l,int r,int L,int R) {
    		if(l >= L && r <= R) return node[i].sum;
    		int mid = l + r >> 1;
    		if(mid >= R) return query(node[i].ls,l,mid,L,R);
    		else if(L > mid) return query(node[i].rs,mid + 1,r,L,R); 
    		return query(node[i].ls,l,mid,L,mid) + query(node[i].rs,mid + 1,r,mid + 1,R);
    	}
    }pst;
    
    bool check(int i,int a,int b,int c,int d){
    	int res = 0;
    	if(b + 1 <= c - 1) res += pst.query(rt[i],1,n,b + 1,c - 1).tot;
    	res += pst.query(rt[i],1,n,a,b).rmax;
    	res += pst.query(rt[i],1,n,c,d).lmax;
    	return res >= 0;
    } 
    
    
    
    
    int main(){
    	n = rd();
    	for(int i = 1;i <= n;i++){
    		a[i].fi = rd();
    		a[i].se = i;
    	}
    	sort(a + 1,a + n + 1);
    	pst.build(rt[1],1,n);
    	for(int i = 2;i <= n;i++){
    		rt[i] = rt[i - 1];
    		pst.update(rt[i],1,n,a[i - 1].se);
    	}
    	int m = rd();
    	int last = 0;
    	while(m--){
    		int c[4];
    		for(int i = 0;i < 4;i++)
    			c[i] = rd(),c[i] = (c[i] + last) % n + 1;
    		sort(c,c + 4);
    		int l = 1,r = n;
    		while(l < r) {
    			int mid = l + r + 1 >> 1;
    			if(check(mid,c[0],c[1],c[2],c[3]))
    				l = mid;
    			else r = mid - 1;
    		}
    		last = a[l].fi;
    		printf("%d
    ",last);
    	}
    }
    
  • 相关阅读:
    利用outlook发送邮件的代码,其实就一句话,哈哈~~
    一个或多个数据库无法访问,因而不会在数据库访问选项卡中显示
    窗口碰壁弹回的浮动广告代码
    DataFormatString格式化数据及格式化时间失效的问题
    弹出并转向代码
    常用运行命令
    post和get
    自己总结的手动生成gridview导出excel的方法
    Spring boot download file
    RESTful WebService 入门实例
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14639712.html
Copyright © 2020-2023  润新知