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$。

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define Rint register int
 4 using namespace std;
 5 const int N = 20003;
 6 int n, Q, q[4], lans, a[N], id[N], root[N], ls[N << 5], rs[N << 5], cnt;
 7 struct Node {
 8     int sum, lmax, rmax;
 9     inline Node(int s = 0, int l = 0, int r = 0): sum(s), lmax(l), rmax(r){}
10     inline Node operator + (const Node &o) const {
11         return Node(sum + o.sum, max(lmax, sum + o.lmax), max(o.rmax, o.sum + rmax));
12     }
13 } seg[N << 5];
14 inline void pushup(int x){
15     seg[x] = seg[ls[x]] + seg[rs[x]];
16 }
17 inline void build(int &x, int L, int R){
18     x = ++ cnt;
19     if(L == R){
20         seg[x] = Node(1, 1, 1);
21         return;
22     }
23     int mid = L + R >> 1;
24     build(ls[x], L, mid);
25     build(rs[x], mid + 1, R);
26     pushup(x);
27 }
28 inline void change(int &nx, int ox, int L, int R, int pos){
29     nx = ++ cnt;
30     ls[nx] = ls[ox]; rs[nx] = rs[ox];
31     if(L == R){
32         seg[nx] = Node(-1, -1, -1);
33         return;
34     }
35     int mid = L + R >> 1;
36     if(pos <= mid) change(ls[nx], ls[ox], L, mid, pos);
37     else change(rs[nx], rs[ox], mid + 1, R, pos);
38     pushup(nx);
39 }
40 inline Node query(int x, int L, int R, int l, int r){
41     if(!x || l > r) return Node();
42     if(l <= L && R <= r) return seg[x];
43     int mid = L + R >> 1;
44     if(r <= mid) return query(ls[x], L, mid, l, r);
45     else if(mid < l) return query(rs[x], mid + 1, R, l, r);
46     else return query(ls[x], L, mid, l, r) + query(rs[x], mid + 1, R, l, r);
47 }
48 inline int solve(int a, int b, int c, int d){
49     int l = 1, r = n, mid, tmp;
50     while(l <= r){
51         mid = l + r >> 1;
52         tmp = query(root[mid], 1, n, a, b).rmax + query(root[mid], 1, n, b + 1, c - 1).sum + query(root[mid], 1, n, c, d).lmax;
53         if(tmp >= 0) l = mid + 1;
54         else r = mid - 1;
55     }
56     return id[r];
57 }
58 int main(){
59     scanf("%d", &n);
60     for(Rint i = 1;i <= n;i ++){
61         scanf("%d", a + i); id[i] = i; 
62     }
63     sort(id + 1, id + n + 1, [](int x, int y) -> bool {return a[x] < a[y];});
64     build(root[1], 1, n);
65     for(Rint i = 1;i < n;i ++)
66         change(root[i + 1], root[i], 1, n, id[i]);
67     scanf("%d", &Q);
68     while(Q --){
69         for(Rint i = 0;i < 4;i ++){
70             scanf("%d", q + i);
71             q[i] = (q[i] + lans) % n + 1;
72         }
73         sort(q, q + 4);
74         printf("%d\n", lans = a[solve(q[0], q[1], q[2], q[3])]);
75     }
76 }
View Code

 

转载于:https://www.cnblogs.com/AThousandMoons/p/10630747.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值