版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/83008197
创送门:洛谷 P1801
题目大意
给定两个操作
- :把 元素放进
- : 加 ,然后输出 中第 小的数( 的初值为 )
分析
题意很明了,就是动态地求区间第
大值。
方法有很多,这里提供两种。
- 权值线段树/树状数组
离散化是不用说的吧
如果做过逆序对的话应该会比较熟悉。用每个节点表示该点对应的数值是否存在。要找第 大值的话只需要找到前缀和为 的点即可。
树状数组的求法可以说是查询前缀和的逆操作,明确好每个节点管理的范围,模拟模拟即可,保证不会重复计算的。
点 所管理的区间 - 对顶堆
利用一个小根堆与一个大根堆来维护序列。
将前 小的数放到大根堆去,其余的全部丢到小根堆。实时维护即可。
代码
- 权值树状数组
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>- **权值树状数组**
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
int qes[2][200005];
int cnt, num[200005];
int bit[200005];
int power[20];
int limit;
IL int lowbit(int x) { return x& (-x); }
IL void add(int x)
{
for(; x <= cnt; x += lowbit(x))
++bit[x];
}
IL int find_k(int k)
{
int ans = 0, tot = 0;
for(int i = limit; i >= 0; --i)
{
ans += power[i];
if(ans >= cnt || tot + bit[ans] >= k)
ans -= power[i];
else
tot += bit[ans];
}
return ans + 1;
}
int main()
{
int n = read(), m = read();
power[0] = 1;
for(int i = 1; i; ++i)
{
power[i] = power[i - 1] << 1;
if(power[i] > n)
{
limit = i - 1;
break;
}
}
for(int i = 1; i <= n; ++i)
{
num[++cnt] = qes[0][i] = read();
}
for(int i = 1; i <= m; ++i)
qes[1][i] = read();
sort(num + 1, num + cnt + 1);
cnt = unique(num + 1, num + cnt + 1) - (num + 1);
for(int i = 1, j = 1, x, t = 0; i <= n; ++i)
{
x = lower_bound(num + 1, num + cnt + 1, qes[0][i]) - num;
add(x);
for(; j <= m && qes[1][j] == i; ++j)
{
printf("%d\n", num[find_k(++t)]);
}
}
return 0;
}
- 对顶堆
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
int K = 0;
struct node
{
priority_queue<int>Q1;
priority_queue<int , vector<int>, greater<int> >Q2;
int t1, t2;
IL void change()
{
for(; t1 > K;) { Q2.push(Q1.top()); Q1.pop(); ++t2; --t1; }
for(; t1 < K;) { Q1.push(Q2.top()); Q2.pop(); ++t1; --t2; }
}
IL void add(int x)
{
if(!t1 || Q1.top() >= x) { Q1.push(x); ++t1;}
else { Q2.push(x); ++t2; }
change();
}
IL int get()
{
return Q1.top();
}
}a;
int qes[2][200005];
int main()
{
int n = read(), m = read();
for(int i = 1; i <= n; ++i) qes[0][i] = read();
for(int i = 1; i <= m; ++i) qes[1][i] = read();
for(int i = 1, j = 1; i <= n && j <= m; ++i)
{
a.add(qes[0][i]);
for(; j <= m && qes[1][j] == i; ++j)
{
++K;
a.change();
printf("%d\n", a.get());
}
}
return 0;
}