BZOJ3262陌上花开 树状数组+Treap

三个属性, 以第一个属性为关键字从小到大排序, 那么考虑一朵花的等级, 只需考虑排在其前面的花的其他属性(特殊情况是有相同的花,根据题意,对一段相同的花,以排在最后的一朵花的答案为准),那么后面的操作就不用考虑第一个属性了 第二三维可以用树状数组加Treap解决, 以每朵花第二属性数值作为位置(因为最大属性k < 2e5, 可以不用离散化, 直接用属性的数值对应树状数组中的下标), 树状数组的每个节点建一颗Treap, 这颗Treap里存的是相应区间里的花的第三个属性, 询问时类似于树状数组求前缀和, 依次将询问的花的位置的前面这一段分成不超过logk棵Treap对应的区间, 在这些区间里可以找出, 由于是以第二属性为位置插入到树状数组里的, 保证前面一段区间的第二属性都是不超过我们询问的花的第二属性, 只要在这不超过logk棵Treap里找出第三属性不超过询问的花的数量, 就是三个属性均不超过询问的花的三个属性的花的数量

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn = 2e5 + 7, maxk = 2e5 + 7, maxnd = 1e6 + 7;

void readin(int &ret) {
    ret = 0; int f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9') ret *= 10, ret += ch - '0', ch = getchar();
    ret *= f;
}

struct flower {
	int s, c, m, id, ans;
	void read() {
		readin(s); readin(c); readin(m);
	}
} f[maxn];
bool cmp(const flower& a, const flower& b) {
	return a.s < b.s || (a.s == b.s && a.c < b.c) || (a.s == b.s && a.c == b.c && a.m < b.m);
}

bool ssame(const flower& a, const flower& b) {
	return a.s == b.s && a.c == b.c && a.m == b.m;
} 
int n, k, siz, ans[maxn], root[maxn], sz[maxnd], val[maxnd], rnd[maxnd], cnt[maxnd], c[maxnd][2];
void update(int k) {
	sz[k] = sz[c[k][0]] + sz[c[k][1]] + cnt[k];
}
void rotate(int &k, int ch) {
	int t = c[k][ch]; c[k][ch] = c[t][ch ^ 1]; c[t][ch ^ 1] = k;
	sz[t] = sz[k]; update(k); k = t;
}
void insert(int &k, int x) {
	if(!k) {
		val[k = ++siz] = x;
		rnd[k] = rand();
		sz[k] = cnt[k] = 1;
		c[k][0] = c[k][1] = 0;
	} else if(val[k] == x) sz[k]++, cnt[k]++;
	else {
		sz[k]++;
		int d = val[k] < x;
		insert(c[k][d], x);
		if(rnd[c[k][d]] < rnd[k]) rotate(k, d);
	}
}
int find(int k, int x) {
	if(!k) return 0;
	if(val[k] == x) return sz[c[k][0]] + cnt[k];
	if(val[k] > x) return find(c[k][0], x);
	return sz[c[k][0]] + cnt[k] + find(c[k][1], x);
} //find(k, x)找出节点k为根的子树中, 权值不大于x的节点数量
#define lowbit(x) (x&-x)
void ins(int pos, int x) {
	while(pos <= k) {
		insert(root[pos], x);
		pos += lowbit(pos);
	}
}
int query(int pos, int x) {
	int ret = 0;
	while(pos > 0) {
		ret += find(root[pos], x);
		pos -= lowbit(pos);
	}
	return ret;
}

int top, stk[maxn], num[maxn];
int main() {
	readin(n); readin(k);
	for(int i = 1; i <= n; i++) f[i].read();
	sort(f + 1, f + n + 1, cmp);
	top = 0;
	for(int i = 1; i <= n; i++) {
		if(ssame(f[i], f[i + 1])) stk[++top] = i;//如果有相同的花, 先存到数组里, 直到处理了最后一朵这种花再更新前面的答案
		else {
			f[i].ans = query(f[i].c, f[i].m);
			while(top) f[stk[top--]].ans = f[i].ans;
		}
		ins(f[i].c, f[i].m);//询问了这朵花后再将这朵花插入树状数组中
	} 
	for(int i = 1; i <= n; i++) num[f[i].ans]++;
	for(int i = 0; i <= n - 1; i++) printf("%d\n", num[i]);
	return 0;
}

  

posted @ 2016-02-21 18:33  using_namespace  阅读(353)  评论(0编辑  收藏  举报