luogu2839 [国家集训队]middle
题目链接:洛谷
题目大意:给定一个长度为$n$的序列,每次询问左端点在$[a,b]$,右端点在$[c,d]$的所有子区间的中位数的最大值。(强制在线)
这里的中位数定义为,对于一个长度为$n$的序列排序之后为$a_0,a_1,\ldots,a_{n-1}$,则$a_{\lfloor\frac{n}{2}\rfloor}$为这个序列的中位数。
数据范围:$1\leq n\leq 20000$,$1\leq q\leq 25000$,$1\leq a\leq b\leq c\leq d\leq n$
这道题才是真正的主席树!
首先我们考虑离散化,然后二分答案,判断这些区间的中位数是否有可能$\geq mid$,那怎么判断呢?
我们发现,如果把这个序列的所有$\geq mid$的数改为1,$<mid$的数改为$-1$,则上述条件等价于这个新的数列之和非负。(这是一个非常神仙的套路)
所以我们对于所有的数$a_i$,预处理出这个1/-1的序列,但是这样空间会爆炸。
我们发现这些序列中,$a_{i-1}$和$a_i$的序列之间仅有一位不同。
于是主席树闪亮登场。
然后判断一下左端点在$[a,b]$,右端点在$[c,d]$的最大子段和,判断一下是否$\geq 0$。
#include<cstdio>
#include<algorithm>
#define Rint register int
using namespace std;
const int N = ;
int n, Q, q[], lans, a[N], id[N], root[N], ls[N << ], rs[N << ], cnt;
struct Node {
int sum, lmax, rmax;
inline Node(int s = , int l = , int r = ): sum(s), lmax(l), rmax(r){}
inline Node operator + (const Node &o) const {
return Node(sum + o.sum, max(lmax, sum + o.lmax), max(o.rmax, o.sum + rmax));
}
} seg[N << ];
inline void pushup(int x){
seg[x] = seg[ls[x]] + seg[rs[x]];
}
inline void build(int &x, int L, int R){
x = ++ cnt;
if(L == R){
seg[x] = Node(, , );
return;
}
int mid = L + R >> ;
build(ls[x], L, mid);
build(rs[x], mid + , R);
pushup(x);
}
inline void change(int &nx, int ox, int L, int R, int pos){
nx = ++ cnt;
ls[nx] = ls[ox]; rs[nx] = rs[ox];
if(L == R){
seg[nx] = Node(-, -, -);
return;
}
int mid = L + R >> ;
if(pos <= mid) change(ls[nx], ls[ox], L, mid, pos);
else change(rs[nx], rs[ox], mid + , R, pos);
pushup(nx);
}
inline Node query(int x, int L, int R, int l, int r){
if(!x || l > r) return Node();
if(l <= L && R <= r) return seg[x];
int mid = L + R >> ;
if(r <= mid) return query(ls[x], L, mid, l, r);
else if(mid < l) return query(rs[x], mid + , R, l, r);
else return query(ls[x], L, mid, l, r) + query(rs[x], mid + , R, l, r);
}
inline int solve(int a, int b, int c, int d){
int l = , r = n, mid, tmp;
while(l <= r){
mid = l + r >> ;
tmp = query(root[mid], , n, a, b).rmax + query(root[mid], , n, b + , c - ).sum + query(root[mid], , n, c, d).lmax;
if(tmp >= ) l = mid + ;
else r = mid - ;
}
return id[r];
}
int main(){
scanf("%d", &n);
for(Rint i = ;i <= n;i ++){
scanf("%d", a + i); id[i] = i;
}
sort(id + , id + n + , [](int x, int y) -> bool {return a[x] < a[y];});
build(root[], , n);
for(Rint i = ;i < n;i ++)
change(root[i + ], root[i], , n, id[i]);
scanf("%d", &Q);
while(Q --){
for(Rint i = ;i < ;i ++){
scanf("%d", q + i);
q[i] = (q[i] + lans) % n + ;
}
sort(q, q + );
printf("%d\n", lans = a[solve(q[], q[], q[], q[])]);
}
}
luogu2839 [国家集训队]middle的更多相关文章
- Luogu2839 [国家集训队]middle 题解
题目很好,考察对主席树的深入理解与灵活运用. 首先看看一般解决中位数的思路,我们二分一个 \(mid\),将区间中 \(\ge mid\) 的数置为 \(1\),小于的置为 \(-1\),然后求区间和 ...
- [国家集训队]middle 解题报告
[国家集训队]middle 主席树的想法感觉挺妙的,但是这题数据范围这么小,直接分块草过去不就好了吗 二分是要二分的,把\(<x\)置\(-1\),\(\ge x\)的置\(1\),于是我们需要 ...
- [国家集训队]middle
[国家集训队]middle 题目 解法 开\(n\)颗线段树,将第\(i\)颗线段树中大于等于第\(i\)小的数权值赋为1,其他的则为-1,对于每个区间维护一个区间和,最大前缀和,最大后缀和. 然后二 ...
- P2839 [国家集训队]middle
P2839 [国家集训队]middle 好妙的题啊,,,, 首先二分一个答案k,把数列里>=k的数置为1,=0就是k>=中位数,<0就是k<中位数 数列的最大和很好求哇 左边的 ...
- CF484E Sign on Fence && [国家集训队]middle
CF484E Sign on Fence #include<bits/stdc++.h> #define RG register #define IL inline #define _ 1 ...
- 【LG2839】[国家集训队]middle
[LG2839][国家集训队]middle 题面 洛谷 题解 按照求中位数的套路,我们二分答案\(mid\),将大于等于\(mid\)的数设为\(1\),否则为\(-1\). 若一个区间和大于等于\( ...
- BZOJ.2653.[国家集训队]middle(可持久化线段树 二分)
BZOJ 洛谷 求中位数除了\(sort\)还有什么方法?二分一个数\(x\),把\(<x\)的数全设成\(-1\),\(\geq x\)的数设成\(1\),判断序列和是否非负. 对于询问\(( ...
- 解题:国家集训队 Middle
题面 求中位数的套路:二分,大于等于的设为1,小于的设为-1 于是可以从小到大排序后依次加入可持久化线段树,这样每次只会变化一个位置 那左右端点是区间怎么办? 先把中间的算上,然后维护每个区间左右两侧 ...
- [洛谷P2839][国家集训队]middle
题目大意:给你一个长度为$n$的序列$s$.$Q$个询问,问在$s$中的左端点在$[a,b]$之间,右端点在$[c,d]$之间的子段中,最大的中位数. 强制在线. 题解:区间中位数?二分答案,如果询问 ...
随机推荐
- 使用protobuf编译onnx.proto过程中的一些问题总结
使用git clone下载protobuf的源代码,然后git checkout到branch2.7.0: 编译protobuf,先在代码顶层目录执行./configure,然后执行make,成功后执 ...
- MYSQL 优化器 源码解析
http://www.unofficialmysqlguide.com/introduction.html https://dev.mysql.com/doc/refman/8.0/en/explai ...
- [Memcached] telnet命令
一:连接命令 在windows下的cmd或者Linux执行 telnet 127.0.0.1 11211 (如果此处报错"telnet不是内部或外部命令",一定是没有安装telne ...
- hdoj:2071
Max Num Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Sub ...
- Android开发怎么让自己的APP UI漂亮、大方(配色篇二)
我们在没有效果图的app开发中有一件事情肯定很头疼:一个按钮的调色改过来改过去,还是很难看,最终只能暂时作罢,浪费了大量的开发时间和精力.开发规范篇见Android开发怎么让自己的APP UI漂亮.大 ...
- js 模仿jquery 写个简单的小demo
<div id="div" style="background:red;width:100px;height:300px"> 123123123 & ...
- DatagramSocket(邮递员):对应数据报的Socket概念,不需要创建两个socket,不可使用输入输出流。
UDP编程: DatagramSocket(邮递员):对应数据报的Socket概念,不需要创建两个socket,不可使用输入输出流. DatagramPacket(信件):数据包,是UDP下进行传输数 ...
- NuGet Packages are missing,This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.
错误内容 This project references NuGet package(s) that are missing on this computer. Use NuGet Package R ...
- A股滚动净利润增速最高排名
最近2年(共8个季度)的滚动净利润都在增长,且平均增速超过10%. 计算举例:滚动净利润增速 = ((2018Q1 到 2018Q4的净利润之和) / (2017Q4 到 2018Q3的净利润之和) ...
- oracle 聚合函数 LISTAGG ,将多行结果合并成一行
LISTAGG( to_char(Item_Category_Name), ',') WITHIN GROUP(ORDER BY Item_Category_Name) -- 将 Item_Cate ...