題目描述
給定一個長度爲n的子序列,有m次詢問,每次詢問給定一個 k 和 pos,表示求長度爲 k 的最大子序列之和的第 pos 位是什麼數字。同時每個最大子序列之和要求滿足字典序最小
思路
題目給定範圍 ,很容易想到對於詢問長度爲 k 的最大求和子序列時,只要貪心的把每個最大的數且位置更靠前的數取出來就行,然後每次去查詢第 pos 個數字是什麼再輸出。因爲這個插入狀態是動態的,所以在查詢過程中也是動態的,先要將所有查詢結果存到一個優先隊列裏去
這個優先隊列以長度 k 爲優先級,同時記錄查詢的位置 pos 和第幾個答案 id
每次記錄最優點的代碼
struct node {
int num, pos;
friend bool operator < (node a, node b) {
if(a.num == b.num) return a.pos < b.pos;
return a.num > b.num;
}
}a[N];
記錄詢問狀態的代碼
struct query {
int k, pos, id;
friend bool operator < (query a, query b) {
return a.k > b.k;
}
};
priority_queue<query> q;
每次先查詢長度短的,同時插入這個點的位置。這一部分用樹狀數組維護,這個點也是我比賽過程中一直沒有想到的點,導致卡了好久。用樹狀數組維護可以保證每次可以有序的插入這個點的複雜度在logn,每次查詢通過二分去查詢所要求的點,可以將整體時間複雜度降到mlogn的複雜度。
查詢pos的代碼
int query(int x) {
int res = 0;
for(int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
int find(int pos) {
int l = 1, r = n;
int res = 0;
while(l <= r) {
int mid = l + r >> 1;
if(query(mid) >= pos) {
res = mid;
r = mid - 1;
} else l = mid + 1;
}
return res;
}
代碼
struct node {
int num, pos;
friend bool operator < (node a, node b) {
if(a.num == b.num) return a.pos < b.pos;
return a.num > b.num;
}
}a[N];
struct query {
int k, pos, id;
friend bool operator < (query a, query b) {
return a.k > b.k;
}
};
priority_queue<query> q;
int tr[N], num[N], ans[N];
int x, n;
int lowbit(int x) {
return x & -x;
}
void update(int x, int c) {
for(int i = x; i <= n; i += lowbit(i)) tr[i] += c;
}
int query(int x) {
int res = 0;
for(int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
int find(int pos) {
int l = 1, r = n;
int res = 0;
while(l <= r) {
int mid = l + r >> 1;
if(query(mid) >= pos) {
res = mid;
r = mid - 1;
} else l = mid + 1;
}
return res;
}
void solve() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
a[i] = {num[i], i};
}
sort(a + 1, a + 1 + n);
int m;
scanf("%d", &m);
for(int i = 1; i <= m; i++) {
int k, pos;
scanf("%d%d", &k, &pos);
q.push({k, pos, i});
}
x = 0;
while(!q.empty()) {
int cnt = q.top().k, pos = q.top().pos, id = q.top().id;
q.pop();
while(x < cnt) {
++x;
update(a[x].pos, 1);
}
int p = find(pos);
ans[id] = num[p];
}
for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);
}