题目链接:http://codeforces.com/problemset/problem/668/D
题意: 有一个时间轴一个multiset容器,执行n(1 ~ 1e5)次操作:
操作1 是 在第a时刻 向容器中加入一个数b,
操作2 是 在第a时刻 从容器中取出一个数b,
操作3 时 输出在第a时刻 容器中b的数量。
思路:刚开始看到这题就像线段树或主席树,后面发现其实就只是计算个前缀和,以时间的前缀和,但这里的数据很大1e9的时间,b的范围也是1e9,但是总的操作次数只有1e5所以我们可以开个map的数组记录时间轴,再用一个map来存每一个出现的数字b这样map的数组大小就可以只开1e5,因为最多存1e5个不同的数字,用树状数组来计算前缀和,这样map数组中的数字最多也就记录log(1e9),也就是数组的每个map元素记录时间不超过30个,内存就妥妥的了。
接下来就是实现了:
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <string>
#include <cmath>
#include <stack>
#define ll long long
#define ull unsigned long long
#define exp 0.00000001
using namespace std;
const int mxx = 1e6+5;
const int mx = 1e9+5;
map<int, int>ma[mxx];///ma[每个数字b(第几个数)][时间轴];
map<int, int>mma;///每个数字b离散为第几个没出现的数
///树状数组模板。。。
int bit(int x)
{
return x&(-x);
}
void up(int x, int y, int k)
{
while (x < mx)
{
ma[y][x] += k;///k为1时数字进来,-1时代表出去。。。。
x += bit(x);
}
return;
}
int qry(int x, int y)
{
int ans = 0;
while (x)
{
ans += ma[y][x];
x -= bit(x);
}
return ans;
}
int main()
{
int n, t, a, b, cnt = 1;
scanf("%d", &n);
for (int i = 0; i < n; ++i)
{
scanf("%d%d%d", &t, &a, &b);
if (!mma[b] && t == 1) mma[b] = cnt++;///每种数字,这就算是简略的离散了
if (t == 1)
up(a, mma[b], 1);
else if (t == 2)
up(a, mma[b], -1);
else printf("%d\n", qry(a, mma[b]));
}
return 0;
}