BZOJ 2653 middle 题解

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

给一个序列,并进行一些询问。每次询问起点在[a,b],终点在[c,d]的序列的中位数。

题解:首先有一个思路:对于一个序列S,假设它的中位数是m,则S中>=m的元素个数一定>=n

那么对于一个序列S和一个数m,我们将>=m的元素设置为1,其余为-1,得到一个新数列S‘。则$\sum S‘$ >=0

对于每个询问我们二分一下m即可。如果在区间[a,d]内有一段包含[b,c]的连续子序列的和>=0,则答案>=当前二分的值。

求最大子序列的和相信大家都会做。。用线段树维护lmax,rmax,sum值即可

但是如果每次都暴力构建线段树的话太慢了。。和暴力差不了多少

于是我们可以用可持久化线段树做。。

然后这题就解决了。。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define fr first
 4 #define sc second
 5 const int MAXN=20000+5;
 6 const int INF=~0U>>1;
 7 struct Info{
 8     int sum,maxl,maxr;
 9     Info(int v) {sum=maxl=maxr=v;}
10     Info() {}
11 };
12 Info operator+(const Info& a,const Info& b)
13 {
14     Info ans;
15     ans.sum=a.sum+b.sum;
16     ans.maxl=std::max(a.maxl,a.sum+std::max(0,b.maxl));
17     ans.maxr=std::max(b.maxr,b.sum+std::max(0,a.maxr));
18     return ans;
19 }
20 struct Tree{
21     int l,r;
22     Info v;
23     Tree* pl,*pr;
24     Tree(int l,int r,int all):l(l),r(r)
25     {
26         if(l+1==r)
27         {
28             v=Info(all);
29             return;
30         }
31         int m=(l+r)>>1;
32         pl=new Tree(l,m,all);
33         pr=new Tree(m,r,all);
34         v=pl->v+pr->v;
35     }
36     Tree(int l,int r,Tree* pl,Tree* pr):l(l),r(r),pl(pl),pr(pr) {v=pl->v+pr->v;}
37     Info query(int L,int R)
38     {
39         if(L<=l && R>=r) return v;
40         int m=(l+r)>>1;
41         if(R<=m) return pl->query(L,R);
42         else if(L>=m) return pr->query(L,R);
43         else return pl->query(L,R)+pr->query(L,R);
44     }
45     Tree* change(int pos,int w)
46     {
47         if(l+1==r) return new Tree(l,r,w);
48         int m=(l+r)>>1;
49         if(pos<m) return new Tree(l,r,pl->change(pos,w),pr);
50         else return new Tree(l,r,pl,pr->change(pos,w));
51     }
52 };
53 typedef std::pair<int,int> P;
54 P ps[MAXN];
55 Tree* root[MAXN];
56 int n;
57 inline bool judge(int v,int a,int b,int c,int d)    //[a,b) [c,d)
58 {
59     Tree* r=root[v];
60     return (r->query(a,b).maxr+(b<c?r->query(b,c).sum:0)+r->query(c,d).maxl)>=0;
61 }
62 int main()
63 {
64     scanf("%d",&n);
65     for(int i=0;i<n;++i)
66     {
67         int t;
68         scanf("%d",&t);
69         ps[i]=P(t,i);
70     }
71     std::sort(ps,ps+n);
72     root[0]=new Tree(0,n,1);
73     for(int i=1;i<n;++i)
74         root[i]=root[i-1]->change(ps[i-1].sc,-1);
75     int q,last=0;
76     scanf("%d",&q);
77     while(q--)
78     {
79         int t[4];
80         for(int i=0;i<4;++i) scanf("%d",t+i),t[i]=(t[i]+last)%n;
81         std::sort(t,t+4);
82         int l=0,r=n;
83         while(l+1<r)
84         {
85             int m=(l+r)>>1;
86             if(judge(m,t[0],t[1]+1,t[2],t[3]+1)) l=m;
87             else r=m;
88         }
89         printf("%d\n",ps[l].fr);
90         last=ps[l].fr;
91     }
92     return 0;
93 }

时间: 2024-11-07 10:56:36

BZOJ 2653 middle 题解的相关文章

BZOJ 2653: middle

2653: middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1536  Solved: 855[Submit][Status][Discuss] Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置

bzoj 2653 middle (主席树+二分)

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 2653 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整. 给你一个长度为n的序列s. 回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d. 位置也从0开始标号. 强制在线. 解法: 首先可以想到的是二分答案,再判断是否满足条件 . 对于答案x,我们将原数组中大于等于x的数记1,小于的记为-1,

bzoj 2653 middle (可持久化线段树)

middle Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1981  Solved: 1097[Submit][Status][Discuss] Description 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 其中a<b<c<d.位置也从0开始标号

BZOJ 2653 middle | 主席树

题目: http://www.lydsy.com/JudgeOnline/problem.php?id=2653 题解: 设答案为ans,把大于等于ans的记为1,小于的记为-1,这样可以知道当前ans是大了还是小了 然后二分答案,就是求最大子段和的问题,根据网上的题解:[b,c]是必选的,然后选[a,b]和[c,d]的最大字段和就行了 #include<cstdio> #include<cstring> #include<algorithm> #define N 20

BZOJ 2653 middle 二分答案+可持久化线段树

题目大意:给定一个长度为n的序列,求当子序列s的左端点在[a,b],右端点在[c,d]时的最大中位数 其中当序列长度为偶数时中位数定义为中间两个数中较大的那个 很难想的一道题 具体题解见 http://blog.csdn.net/acm_cxlove/article/details/8566093 说的很详细 区间处理那里 [b,c]是必选的 [a,b)和(c,d]每段取最大加和 否则re恒>=0 #include<cstdio> #include<cstring> #inc

BZOJ 2653: middle [主席树 中位数]

传送门 题意: 一个长度为n的序列a,设其排过序之后为b,其中位数定义为b[n/2],其中a,b从0开始标号,除法取下整.给你一个 长度为n的序列s.回答Q个这样的询问:s的左端点在[a,b]之间,右端点在[c,d]之间的子序列中,最大的中位数. 我会使用一些方式强制你在线. 最后一句话太可怕了$QAQ$ 首先需要知道怎么求中位数: 二分答案,$\ge$的为$1$,$<$的为$-1$,如果和$\ge 0$说明当前答案$\le$中位数 最大中位数?$GSS$! 只要求$[a,b].rm+(b,c)

BZOJ 1179 Atm 题解

BZOJ 1179 Atm 题解 SPFA Algorithm Tarjan Algorithm Description Input 第一行包含两个整数N.M.N表示路口的个数,M表示道路条数.接下来M行,每行两个整数,这两个整数都在1到N之间,第i+1行的两个整数表示第i条道路的起点和终点的路口编号.接下来N行,每行一个整数,按顺序表示每个路口处的ATM机中的钱数.接下来一行包含两个整数S.P,S表示市中心的编号,也就是出发的路口.P表示酒吧数目.接下来的一行中有P个整数,表示P个有酒吧的路口

函数式trie思想 &amp; Bzoj 3261 &amp; 3166 题解

[原题1] 3261: 最大异或和 Time Limit: 10 Sec  Memory Limit: 512 MB Submit: 497  Solved: 215 [Submit][Status] Description 给定一个非负整数序列 {a},初始长度为 N. 有   M个操作,有以下两种操作类型: 1 .A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1. 2 .Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得: a[p] xor a[

BZOJ 1008 越狱 题解 裸快速幂

BZOJ 1008 越狱 题解 裸快速幂 1008: [HNOI2008]越狱 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 7887  Solved: 3372[Submit][Status][Discuss] Description 监狱有连续编号为1...N的N个房间,每个房间关押一个犯人,有M种宗教,每个犯人可能信仰其中一种.如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱 Input 输入两个整数M,N.1<=M<