Codeforces 669E cdq分治

题意:你需要维护一个multiset,支持以下操作:

1:在某个时间点向multiset插入一个数。

2:在某个时间点在multiset中删除一个数。

3:在某个时间点查询multiset的某个数的个数。

思路:该题相当于要构建一个在任意位置插入,并查询前缀操作的某个值的多少。乍一看比较棘手,搞不好还要数据结构的嵌套。但是转化一下思路,用cdq分治这题非常简单。分治过程中按时间排序即可,用map维护前半部分产生的影响,后面如果有查询在map中查询即可。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
struct query{
	int flag, t, val, id;
};
query q[maxn], tmp[maxn];
int ans[maxn], tot;
map<int, int> mp;
void cdq(int l, int r) {
	if(l == r) return;
	int mid = (l + r) >> 1;
	cdq(l, mid);
	cdq(mid + 1, r);
	int l1 = l, l2 = mid + 1, pos = l;
	mp.clear();
	while(l1 <= mid && l2 <= r) {
		if(q[l1].t < q[l2].t) {
			if(q[l1].flag == 1) mp[q[l1].val]++;
			else if(q[l1].flag == 2) mp[q[l1].val]--;
			tmp[pos++] = q[l1++];
		} else {
			if(q[l2].flag == 3) {
				ans[q[l2].id] += mp[q[l2].val];
			}
			tmp[pos++] = q[l2++];
		}
	}
	while(l1 <= mid) tmp[pos++] = q[l1++];
	while(l2 <= r) {
		if(q[l2].flag == 3) {
			ans[q[l2].id] += mp[q[l2].val];
		}
		tmp[pos++] = q[l2++];
	}
	for (int i = l; i <= r; i++)
		q[i] = tmp[i];
}
int main() {
	int n;
	scanf("%d", &n);
	for (int i = 1; i <= n; i++) {
		scanf("%d%d%d", &q[i].flag, &q[i].t, &q[i].val);
		if(q[i].flag == 3) q[i].id = ++tot;
	}
	cdq(1, n);
	for (int i = 1; i <= tot; i++) {
		printf("%d
", ans[i]);
	}
} 

  

原文地址:https://www.cnblogs.com/pkgunboat/p/11158838.html