训练赛20190304 K - Black Box

typeryougishiki

2019-03-06 18:47:55

Personal

这个题的难度主要在于~~反人类的输入~~读题 ## 题面 有一个数组和一个变量i,i初始为0 有两个指令 ADD(x):向数组中放入一个x GET:i加一,然后查询数组中的第i小 ## 输入 M, N, A(1), A(2), ..., A(M), u(1), u(2), ..., u(N) **其中,A(i)为第i次执行ADD命令时的参数,u(i)为在第u(i)次ADD后执行第i次GET**(这里大概把挺多人绕晕了) ## 输出 每次GET查询的结果 ## 关于输入 以样例输入为例 A = {3 1 -4 2 8 -1000 2} u = {1 2 6 6} 就是在第一次,第二次ADD后各执行一次GET,在第6次ADD后执行两次GET ## 题解 这个题乍一看好像是个区间第K大的题,但其实完全不用那么麻烦(这个题整体数据量不是很大而且只有加入新元素没有修改),开俩堆就能解决。 初始化一个大顶堆left和一个小顶堆right,在每次ADD后,维护这两个堆,使left中保存数组中前i小的元素,right则保存更大的元素。在由于get使i加一之后,right堆的堆顶就是第i小的数。 ```cpp #include<iostream> #include<algorithm> #include<queue> #include<string> #include<vector> #pragma warning(disable:4996) using namespace std; typedef long long ll; #define FOR(i,b,e) for(ll i = b;i<=e;i++) #define INT64_MAX 9223372036854775807 #define INT64_MIN -9223372036854775807 priority_queue<ll>tool_left; priority_queue<ll, vector<ll>, greater<ll> > tool_right; ll n; ll a[30010]; ll a_i = 1; ll u[30010]; ll u_i = 1; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); ll m, n, it = 0; bool fis = true; cin >> m >> n; FOR(i, 1, m)cin >> a[i]; FOR(i, 1, n) cin >> u[i]; while (a_i <= m) { if (fis) { tool_right.push(a[a_i]); fis = false; }//特判第一次 else {//保证tool_left中所有值都小于tool_right ll rul = (tool_left.size() > 0 ? tool_left.top(): tool_right.top()); if (rul < a[a_i])tool_right.push(a[a_i]); else tool_left.push(a[a_i]); } while (tool_left.size() < it) { ll np = tool_right.top(); tool_right.pop(); tool_left.push(np); } while (tool_left.size() > it) { ll np = tool_left.top(); tool_left.pop(); tool_right.push(np); } while (u[u_i] == a_i) { it++; cout << (tool_right.top()) << endl; //有可能会出现连续多次get的情况,所以get完之后也要更新两个堆 while (tool_left.size() < it) { ll np = tool_right.top(); tool_right.pop(); tool_left.push(np); } while (tool_left.size() > it) { ll np = tool_left.top(); tool_left.pop(); tool_right.push(np); } u_i++; } a_i++; } return 0; } ```