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 ;
    }
    
  • 相关阅读:
    java OA系统 自定义表单 流程审批 电子印章 手写文字识别 电子签名 即时通讯
    flowable 获取当前任务流程图片的输入流
    最新 接口api插件 Swagger3 更新配置详解
    springboot 集成 activiti 流程引擎
    java 在线考试系统源码 springboot 在线教育 视频直播功能 支持手机端
    阿里 Nacos 注册中心 配置启动说明
    springboot 集成外部tomcat war包部署方式
    java 监听 redis 过期事件
    springcloudalibaba 组件版本关系
    java WebSocket 即时通讯配置使用说明
  • 原文地址:https://www.cnblogs.com/beretty/p/10013559.html
Copyright © 2011-2022 走看看