【樹狀數組+二分,貪心】CF1227-D2. Optimal Subsequences (Hard Version)

點擊跳轉到題目

題目描述

給定一個長度爲n的子序列,有m次詢問,每次詢問給定一個 k 和 pos,表示求長度爲 k 的最大子序列之和的第 pos 位是什麼數字。同時每個最大子序列之和要求滿足字典序最小

思路

題目給定範圍 1n,m2e51 \leq n,m \leq 2e5,很容易想到對於詢問長度爲 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]);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章