Skip to content

Commit

Permalink
20210323
Browse files Browse the repository at this point in the history
  • Loading branch information
TosakaUCW committed Mar 23, 2021
1 parent 088e48e commit ae75b00
Show file tree
Hide file tree
Showing 4 changed files with 180 additions and 3 deletions.
2 changes: 1 addition & 1 deletion content/post/CF_997C.md
@@ -1,5 +1,5 @@
+++
title = 'CF 997C Sky Full of Stars(二项式反演,DP)'
title = 'CF 997C Sky Full of Stars二项式反演,DP)'
date = 2021-03-18T10:47:44+08:00
categories = ['题解']
tags = ['二项式反演', 'DP']
Expand Down
177 changes: 177 additions & 0 deletions content/post/Luogu_P2824.md
@@ -0,0 +1,177 @@
+++
title = 'Luogu P2824 [HEOI2016/TJOI2016]排序(线段树,二分答案)'
date = 2021-03-23T10:50:37+08:00
categories = ['题解']
tags = ['线段树', '二分答案']
+++

[题目链接](https://www.luogu.com.cn/problem/P2824)

{{% question %}}

给出一个 $1$ 到 $n$ 的排列,现在对这个排列序列进行 $m$ 次局部排序,排序分为两种:

- `0 L R` 表示将区间 $[L, R]$ 的数字升序排序
- `1 L R` 表示将区间 $[L, R]$ 的数字降序排序

注意,这里是对下标在区间 $[L, R]$ 内的数排序

最后询问第 $q$ 位置上的数字

$ n, m \leq 10^5$

{{% /question %}}

<!--more-->

## 简要做法

考虑二分答案,对于 $mid$,将原排列中 $\geq mid$ 的数标记为 $1$,$< mid$ 的数标记为 $0$

问题转化为二分一个最大的 $mid$,使得排序后 $mid$ 位置上的数字是 $1$

考虑处理排序

对于区间 $[L, R]$,记区间 $[L, R]$ 内 $1$ 的个数为 $cnt$

若为升序排序,则

$$
\begin{aligned}
\begin{cases}
&[L, R - cnt] \leftarrow 0\\\\
\\\\
&[R - cnt + 1, R] \leftarrow 1
\end{cases}
\end{aligned}
$$

若为降序排序,则

$$
\begin{aligned}
\begin{cases}
&[L + cnt, R] \leftarrow 0\\\\
\\\\
&[L, L + cnt - 1] \leftarrow 1
\end{cases}
\end{aligned}
$$

发现需要一种同时支持快速 区间查询 区间修改 单点查询 的数据结构

使用线段树即可,复杂度 $O(m \log^2n)$

## 参考代码

```cpp
#include <stdio.h>
#include <algorithm>
#include <memory.h>

int read(int x = 0, int f = 0, char ch = getchar())
{
while ('0' > ch or ch > '9')
f = ch == '-', ch = getchar();
while ('0' <= ch and ch <= '9')
x = x * 10 + (ch ^ 48), ch = getchar();
return f ? -x : x;
}

const int N = 1e6 + 5;

int n, m, p, ans;
int a[N];
int opt[N], L[N], R[N];

struct Seg_Tree
{
#define ls (p << 1)
#define rs (p << 1 | 1)
#define mid ((l + r) >> 1)
int tag[N << 2], sum[N << 2];
void push_up(int p) { sum[p] = sum[ls] + sum[rs]; }
void push_down(int p, int l, int r)
{
if (!tag[p])
return;
tag[ls] = tag[rs] = tag[p];
if (tag[p] == 1)
sum[ls] = mid - l + 1, sum[rs] = r - mid;
else
sum[ls] = sum[rs] = 0;
tag[p] = 0;
}
void build(int p, int l, int r, int x)
{
tag[p] = 0;
if (l == r)
return sum[p] = a[l] >= x, tag[p] = 0, void();
build(ls, l, mid, x), build(rs, mid + 1, r, x), push_up(p);
}
int query(int p, int l, int r, int x, int y)
{
if (x == l and r == y)
return sum[p];
push_down(p, l, r);
int res = 0;
if (x <= mid)
res += query(ls, l, mid, x, std::min(mid, y));
if (mid < y)
res += query(rs, mid + 1, r, std::max(mid + 1, x), y);
return res;
}
void modify(int p, int l, int r, int x, int y, int val)
{
if (x > r or y < l)
return;
if (x == l and r == y)
return sum[p] = val * (r - l + 1), tag[p] = val ? 1 : -1, void();
push_down(p, l, r);
if (x <= mid)
modify(ls, l, mid, x, std::min(mid, y), val);
if (mid < y)
modify(rs, mid + 1, r, std::max(mid + 1, x), y, val);
push_up(p);
}
#undef ls
#undef rs
#undef mid
} T;

bool judge(int x)
{
T.build(1, 1, n, x);
for (int i = 1; i <= m; i++)
{
int cnt = T.query(1, 1, n, L[i], R[i]);
if (opt[i] == 0)
{
T.modify(1, 1, n, R[i] - cnt + 1, R[i], 1);
T.modify(1, 1, n, L[i], R[i] - cnt, 0);
}
else
{
T.modify(1, 1, n, L[i], L[i] + cnt - 1, 1);
T.modify(1, 1, n, L[i] + cnt, R[i], 0);
}
}
return T.query(1, 1, n, p, p);
}

int main()
{
n = read(), m = read();
for (int i = 1; i <= n; i++)
a[i] = read();
for (int i = 1; i <= m; i++)
opt[i] = read(), L[i] = read(), R[i] = read();
p = read();
for (int L = 1, R = n, mid; L <= R;)
if (judge(mid = L + R >> 1))
ans = mid, L = mid + 1;
else
R = mid - 1;
return printf("%d", ans), 0;
}
```
2 changes: 1 addition & 1 deletion content/post/Luogu_P5505.md
@@ -1,5 +1,5 @@
+++
title = 'Luogu P5505 [JSOI2011]分特产(二项式反演,DP)'
title = 'Luogu P5505 [JSOI2011]分特产二项式反演,DP)'
date = 2021-03-15T20:39:45+08:00
categories = ['题解']
tags = ['二项式反演', 'DP']
Expand Down
2 changes: 1 addition & 1 deletion content/post/Luogu_P6478.md
@@ -1,5 +1,5 @@
+++
title = 'Luogu P6478 [NOI Online #2 提高组] 游戏(二项式反演,树形DP)'
title = 'Luogu P6478 [NOI Online #2 提高组] 游戏二项式反演,树形DP)'
date = 2021-03-16T18:19:45+08:00
categories = ['题解']
tags = ['二项式反演', 'DP', '树形DP']
Expand Down

0 comments on commit ae75b00

Please sign in to comment.