黑匣子_NOI导刊2010提高 ---对顶堆/权值树状数组

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27121257/article/details/83008197

创送门洛谷 P1801


题目大意

给定两个操作

  1. A D D ( x ) ADD(x) :把 x x 元素放进 B l a c k B o x BlackBox
  2. G E T GET : i i 1 1 ,然后输出 B l a c k h o x Blackhox 中第 i i 小的数( i i 的初值为 0 0 )

分析

题意很明了,就是动态地求区间第 k k 大值。
方法有很多,这里提供两种。

  1. 权值线段树/树状数组
    离散化是不用说的吧
    如果做过逆序对的话应该会比较熟悉。用每个节点表示该点对应的数值是否存在。要找第 k k 大值的话只需要找到前缀和为 k k 的点即可。
    树状数组的求法可以说是查询前缀和的逆操作,明确好每个节点管理的范围,模拟模拟即可,保证不会重复计算的。
    x x 所管理的区间 [ x l o w b i t ( x ) + 1 , x ] [x - lowbit(x) + 1, x]
  2. 对顶堆
    利用一个小根堆与一个大根堆来维护序列。
    将前 k k 小的数放到大根堆去,其余的全部丢到小根堆。实时维护即可。

代码

  • 权值树状数组
#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;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/83008197