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

    题目描述

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

    给你一个长度为n的序列s。

    回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数。

    其中a<b<c<d。

    位置也从0开始标号。

    我会使用一些方式强制你在线。

    输入输出格式

    输入格式:

    第一行序列长度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]。

    输入保证满足条件。

    输出格式:

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

    输入输出样例

    输入样例#1: 复制

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

    输出样例#1: 复制

    271451044
    271451044
    969056313

    说明

    0:n,Q<=100

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

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


    题解

    可以将中位数问题转化成类似于01序列排序的问题
    每次二分一个中位数
    然后原序列大于等于这个数的设为1
    其余的设为-1
    然后就要找一段区间,使区间左端点在[a,b],右端点在[c,d]
    如果有这样一段区间的值>=0,那么二分的这个数就是合法的
    然后考虑优化这个过程
    显然答案可以分成三部分
    一部分是[b+1,c-1]的必须选择的部分
    然后再维护一个[a,b]的最大后缀和和一个[c,d]的最大前缀和
    这个操作我们可以用主席树来实现
    对于每一个权值建一棵主席树
    维护区间和,最大后缀和和最大前缀和

    题解

    #include<map>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    # define ls t[now].l
    # define rs t[now].r
    const int M = 25005 ;
    using namespace std ;
    inline int read() {
    	char c = getchar() ; int x = 0 , w = 1 ;
    	while(c>'9'||c<'0') { if(c=='-') w = -1 ; c = getchar() ; }
    	while(c>='0'&&c<='9') { x = x*10+c-'0' ; c = getchar() ; }
    	return x*w ;
    }
    
    int n , v[M] , s[M] , rt[M];
    int tot , cnt , val[M] , q[8] ;
    map < int , int > p ;
    vector < int > vec[M] ;
    struct Node {
    	int l , r , Lmax , Rmax , Sum ;
    	inline Node () {  }
    } t[M << 5] ;
    inline void Merge(Node &temp , Node tl , Node tr) {
    	temp.Sum = tl.Sum + tr.Sum ;
    	temp.Lmax = max(tl.Lmax , tl.Sum + tr.Lmax) ;
    	temp.Rmax = max(tr.Rmax , tr.Sum + tl.Rmax) ;
    }
    void Insert(int x , int v , int l , int r , int &now) {
    	t[++tot] = t[now] ; now = tot ;
    	if(l == r) {
    		t[now].Lmax = t[now].Rmax = t[now].Sum = v ;
    		return ;
    	}
    	int mid = (l + r) >> 1 ;
    	if(mid >= x) Insert(x , v , l , mid , ls) ;
    	else Insert(x , v , mid + 1 , r , rs) ;
    	Merge(t[now] , t[ls] , t[rs]) ;
    }
    Node query(int L , int R , int l , int r , int now) {
    	if(l == L && r == R) return t[now] ;
    	int mid = (l + r) >> 1 ;
    	if(mid >= R) return query(L , R , l , mid , ls) ;
    	else if(mid < L) return query(L , R , mid + 1 , r , rs) ;
    	else {
    		Node temp , tl , tr ;
    		tl = query(L , mid , l , mid , ls) ;
    		tr = query(mid + 1 , R , mid + 1  , r , rs) ;
    		Merge(temp , tl , tr) ;
    		return temp ;
    	}
    }
    inline bool chk(int mid) {
    	int Ans = 0 , tmid = 0 , tl = 0 , tr = 0 ;
    	if(q[2] + 1 <= q[3] - 1) tmid = query(q[2] + 1 , q[3] - 1 , 1 , n , rt[mid]).Sum ;
    	tl = query(q[1] , q[2] , 1 , n , rt[mid]).Rmax ;
    	tr = query(q[3] , q[4] , 1 , n , rt[mid]).Lmax ;
    	Ans = tmid + tl + tr ;
    	if(q[2] == q[3]) {
    		if(v[q[2]] > mid) Ans ++ ;
    		else Ans -- ;
    	}
    	return (Ans >= 0) ;
    }
    inline int Solve() {
    	int l = 1 , r = cnt , ret = 0 ;
    	while(l <= r) {
    		int mid = (l + r) >> 1 ;
    		if(chk(mid)) l = mid + 1 , ret = mid ;
    		else r = mid - 1 ;
    	}
    	return val[ret] ;
    }
    int main() {
    	n = read() ;
    	for(int i = 1 ; i <= n ; i ++) {
    		v[i] = read() ;
    		s[i] = v[i] ;
    	}
    	sort(s + 1 , s + n + 1) ;
    	for(int i = 1 ; i <= n ; i ++) {
    		if(i == 1 || s[i] != s[i - 1]) ++ cnt ;
    		p[s[i]] = cnt ; val[cnt] = s[i] ;
    	}
    	for(int i = 1 ; i <= n ; i ++) {
    		v[i] = p[v[i]] ;
    		vec[v[i]].push_back(i) ;
    	}	
    	for(int i = 1 ; i <= n ; i ++) Insert(i , 1 , 1 , n , rt[0]) ;
    	for(int i = 1 ; i <= cnt ; i ++) {
    		rt[i] = rt[i - 1] ;
    		for(int j = 0 , x ; j < vec[i - 1].size() ; j ++) {
    			x = vec[i - 1][j] ;
    			Insert(x , -1 , 1 , n , rt[i]) ;
    		}
    	}
    	int T = read() , LastAns = 0 ;
    	while(T --) {
    		for(int i = 1 ; i <= 4 ; i ++)
    			q[i] = (read() + LastAns) % n + 1 ;
    		sort(q + 1 , q + 5) ;
    		LastAns = Solve() ;
    		printf("%d
    ",LastAns) ;
    	}
    	return 0 ;
    }
    
  • 相关阅读:
    org.dom4j.DocumentException: Error on line 1 of document: 前言中不允许有内容
    学习过程中的随手笔记
    IT技术团队行而有效的管理之道
    九宫格抽奖HTML+JS版
    Nginx负载均衡深入浅出
    PHP 二维数组根据某个字段排序
    MYSQL INSERT INTO SELECT 不插入重复数据
    小米2成功使用google组件的办法(为了coc游戏能登录google账户)
    PHP 数组排序方法总结
    普通标和转让标的回款和还款日期的算法。
  • 原文地址:https://www.cnblogs.com/beretty/p/10013559.html
Copyright © 2011-2022 走看看