CodeForces 669E Little Artem and Time Machine(主席树+树状数组)

题意:维护一个multiset,给出n次询问,有三种类型的操作,分别是增加元素,删除元素,查询元素数量,

每次询问操作有一个时间和一个元素,询问这个时间的时候这个元素的数量。

思路:主席树+树状数组,其中时间可以看成主席树的位置,然后就是用树状数组动态修改主席树中的元素,离散化一下时间和元素然后每次查询输出。

树状数组每个结点都是一棵线段树,表示一个区间内所有元素的数量情况,具体见

动态主席树

#include <bits/stdc++.h>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#define pb push_back
#define mp make_pair
//#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int maxn = 100100;
const int M = 20000000;
int n, m, tot;
int t[maxn];
int lson[M], rson[M], c[M];
int S[maxn];
struct Query {
	int kind;
	int pos, val;
} query[maxn];

void Init_hash(int k) {
	sort(t, t+k);
	m = unique(t, t+k) - t;
}

int Hash(int x) {
	return lower_bound(t, t+m, x) - t;
}

int build(int l, int r) {
	int root = tot++;
	c[root] = 0;
	if(l != r) {
		int mid = (l+r) >> 1;
		lson[root] = build(l, mid);
		rson[root] = build(mid+1, r);
	}
	return root;
}
int Insert(int root, int pos, int val) {
	int newroot = tot++, tmp = newroot;
	int l = 0, r = m-1;
	c[newroot] = c[root] + val;
    while(l < r) {
        int mid = (l+r)>>1;
        if(pos <= mid) {
            lson[newroot] = tot++; rson[newroot] = rson[root];
            newroot = lson[newroot]; root = lson[root];
            r = mid;
        }
        else {
            rson[newroot] = tot++; lson[newroot] = lson[root];
            newroot = rson[newroot]; root = rson[root];
            l = mid+1;
        }
        c[newroot] = c[root] + val;
    }
	return tmp;
}

int lowbit(int x) {
	return x&(-x);
}
int use[maxn];
void add(int x, int pos, int d) {
	while(x <= n) {
		S[x] = Insert(S[x], pos, d);
		x += lowbit(x);
	}
}
int Sum(int x) {
	int ret = 0;
	while (x > 0) {
		ret += c[use[x]];
		x -= lowbit(x);
	}
	return ret;
}
int solve(int pos, int k) {
	int l = 0, r = m-1;
	for (int i = pos; i; i -= lowbit(i)) use[i] = S[i];	
	while (l < r) {
		int mid = (l+r) >> 1;
		if(mid >= k) {
			r = mid;
			for(int i = pos; i; i -= lowbit(i)) use[i] = lson[use[i]];
		}
		else {
			l = mid + 1;
			for(int i = pos; i; i -= lowbit(i)) use[i] = rson[use[i]];
		}		
	}
	return Sum(pos);
}
int tmp[maxn];
int main() {
	//freopen("input.txt", "r", stdin);
	scanf("%d", &n);
	tot = 0;
	m = 0;
	for(int i = 1; i <= n; i++) {
        scanf("%d%d%d", &query[i].kind, &query[i].pos, &query[i].val);
        t[m++] = query[i].val;
        tmp[i] = query[i].pos;
   	}
   	sort(tmp+1, tmp+n+1);
   	for (int i = 1; i <= n; i++)
   		query[i].pos = lower_bound(tmp+1, tmp+n+1, query[i].pos) - tmp;
	Init_hash(m);
	S[0] = build(0, m-1);
	for (int i = 1; i <= n; i++) S[i] = S[0];
	for (int i = 1; i <= n; i++) {
        if (query[i].kind == 1) 
        	add(query[i].pos, Hash(query[i].val), 1);
        else if (query[i].kind == 2)
        	add(query[i].pos, Hash(query[i].val), -1);
        else 
        	printf("%d\n", solve(query[i].pos, Hash(query[i].val)));
    }		
    return 0;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值