黑匣子_NOI導刊2010提高 ---對頂堆/權值樹狀陣列
阿新 • • 發佈:2018-11-10
創送門:洛谷 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;
}