[BZOJ4548]小奇的糖果

[BZOJ4548]小奇的糖果

试题描述

\(N\) 个彩色糖果在平面上。小奇想在平面上取一条水平的线段,并拾起它上方或下方的所有糖果。求出最多能够拾起多少糖果,使得获得的糖果并不包含所有的颜色。

输入

包含多组测试数据,第一行输入一个正整数 \(T\) 表示测试数据组数。

接下来 \(T\) 组测试数据,对于每组测试数据,第一行输入两个正整数 \(N\)\(K\),分别表示点数和颜色数。

接下来 \(N\) 行,每行描述一个点,前两个数 \(x, y (|x|, |y| \le 2^{30} - 1)\) 描述点的位置,最后一个数 \(z (1 \le z ≤ k)\) 描述点的颜色。

输出

对于每组数据在一行内输出一个非负整数 \(ans\),表示答案

输入示例

1
10 3
1 2 3
2 1 1
2 4 2
3 5 3
4 4 2
5 1 2
6 3 1
6 7 1
7 2 3
9 4 2

输出示例

5

数据规模及约定

对于 \(100\%\) 的数据,\(N \le 100000,K \le 100000,T \le 3\)

题解

此题和那道题是双倍经验关系。

然而我那道题的做法在这里直接 T 飞了,所以再讲一个不那么慢的做法。(虽然也是基本垫底)

如果给出的点没有提到所有颜色,就直接输出 \(n\)

枚举不能包含的那个颜色 \(c\),令所有颜色为 \(c\) 的点的集和为 \(S_c\)。将 \(S_c\) 中的点按 \(x\) 坐标排序,然后我们从左到右依次考虑每个点,并以 \(y\) 坐标为关键字维护单调栈,当删除单调栈中的元素时统计一下极大子矩形的答案。询问矩形内部点数可以用主席树一个 \(\log n\) 做。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;
#define rep(i, s, t) for(int i = (s), mi = (t); i <= mi; i++)
#define dwn(i, s, t) for(int i = (s), mi = (t); i >= mi; i--)

int read() {
	int x = 0, f = 1; char c = getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
	return x * f;
}

#define maxn 100010
#define maxnode 2000010
#define pii pair <int, int>
#define x first
#define y second
#define mp(x, y) make_pair(x, y)

int n, K, nX[maxn], nY[maxn];
pii ps[maxn];
vector <pii > col[maxn];
bool cmpy(pii a, pii b) { return a.y < b.y; }

int ToT, rt[maxn], sumv[maxnode], lc[maxnode], rc[maxnode];
void update(int& y, int x, int l, int r, int p) {
	sumv[y = ++ToT] = sumv[x] + 1;
	if(l == r) return ;
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
	if(p <= mid) update(lc[y], lc[x], l, mid, p);
	else update(rc[y], rc[x], mid + 1, r, p);
	return ;
}
int query(int o, int l, int r, int ql, int qr) {
	if(!o) return 0;
	if(ql <= l && r <= qr) return sumv[o];
	int mid = l + r >> 1, ans = 0;
	if(ql <= mid) ans += query(lc[o], l, mid, ql, qr);
	if(qr > mid) ans += query(rc[o], mid + 1, r, ql, qr);
	return ans;
}
int Query(int xl, int xr, int yl, int yr) {
	if(xl > xr || yl > yr) return 0;
	return query(rt[yr], 1, n, xl, xr) - query(rt[yl-1], 1, n, xl, xr);
}

int S[maxn], top;
void work() {
	ToT = 0;
	memset(rt, 0, sizeof(rt));
	memset(lc, 0, sizeof(lc));
	memset(rc, 0, sizeof(rc));
	
	n = read(); K = read();
	rep(c, 1, K) col[c].clear();
	rep(i, 1, n) {
		int x = read(), y = read(), c = read();
		nX[i] = x; nY[i] = y;
		ps[i] = mp(x, y);
		col[c].push_back(ps[i]);
	}
	sort(nX + 1, nX + n + 1);
	sort(nY + 1, nY + n + 1);
	rep(i, 1, n)
		ps[i].x = lower_bound(nX + 1, nX + n + 1, ps[i].x) - nX,
		ps[i].y = lower_bound(nY + 1, nY + n + 1, ps[i].y) - nY;
	rep(c, 1, K) {
		if(!col[c].size()) return (void)printf("%d\n", n);
		rep(i, 0, (int)col[c].size() - 1) {
			pii& p = col[c][i];
			p.x = lower_bound(nX + 1, nX + n + 1, p.x) - nX;
			p.y = lower_bound(nY + 1, nY + n + 1, p.y) - nY;
		}
	}
	sort(ps + 1, ps + n + 1, cmpy);
	int j = 1;
	rep(i, 1, n) {
		rt[i] = rt[i-1];
		while(j <= n && ps[j].y == i) update(rt[i], rt[i], 1, n, ps[j++].x);
	}
	int ans = 0;
	rep(c, 1, K) {
		sort(col[c].begin(), col[c].end());
		// optimus
		rep(i, 0, (int)col[c].size() - 1) ans = max(ans, Query(i ? col[c][i-1].x + 1 : 1, col[c][i].x - 1, 1, n));
		ans = max(ans, Query(col[c][col[c].size()-1].x + 1, n, 1, n));
		// down
		rep(i, 0, (int)col[c].size() - 1) {
			pii now = col[c][i];
			while(top && col[c][S[top]].y > now.y) {
				ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, now.x - 1, 1, col[c][S[top]].y - 1));
				top--;
			}
			S[++top] = i;
		}
		while(top) {
			ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, n, 1, col[c][S[top]].y - 1));
			top--;
		}
		// up
		rep(i, 0, (int)col[c].size() - 1) {
			pii now = col[c][i];
			while(top && col[c][S[top]].y < now.y) {
				ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, now.x - 1, col[c][S[top]].y + 1, n));
				top--;
			}
			S[++top] = i;
		}
		while(top) {
			ans = max(ans, Query(top > 1 ? col[c][S[top-1]].x + 1 : 1, n, col[c][S[top]].y + 1, n));
			top--;
		}
	}
	printf("%d\n", ans);
	return ;
}

int main() {
	int T = read();
	
	while(T--) work();
	
	return 0;
}
posted @ 2018-02-27 16:13  xjr01  阅读(199)  评论(0编辑  收藏  举报