题意: 给出一个二维平面,要求支持三种操作:插入一个点(x,y),删除一个点,以及查询横坐标比给定x大,纵坐标比给定y大的具有最小横坐标的点,输出它的坐标。如果有多个点具有相同x值,输出在满足要求下y值最小的那个。操作次数20W。
解法: 把所有的点离散化后按照y值排序,那么我们需要的答案就是在满足y的情况下找到最小的满足的x值。那么就使用树状数组来实现对y~正无穷这个区间的查询。
对y轴建树,把每个点插到它的y值对应的位置,用树状数组来维护。然后对于每次的询问点(x0,y0),查询y0+1~正无穷区间,在每个位置二分查找最小x值,最后维护一个最小值即为答案,复杂度n*(lgn)^2.
/* ********************************************** Author : Nero Created Time: 2013/9/2 15:13:03 Problem id : CF-19D Problem Name: Points *********************************************** */ #include <stdio.h> #include <string.h> #include <set> #include <algorithm> using namespace std; #define REP(i,a,b) for(int i=(a); i<(int)(b); i++) #define clr(a,b) memset(a,b,sizeof(a)) typedef pair<int,int> P; #define MP make_pair const int INF = 0x3f3f3f3f; const int MAXN = 201000; // 离散化 struct San { int a[MAXN], n; int size() { return n; } void init() { n = 0; } void push(int x) { a[n++] = x; } void doit() { sort(a,a+n); n = unique(a,a+n) - a; } int operator [] (int x) { return lower_bound(a,a+n,x) - a; } }san; struct Query { char c; int x,y; }q[MAXN]; int n; // 树状数组套set set <P> ss[MAXN]; set <P> :: iterator it; inline void add(int p, P node) { for( ; p > 0; p -= p&-p) ss[p].insert(node); } inline void remove(int p, P node) { for( ; p > 0; p -= p&-p) ss[p].erase(node); } inline void query(int p, P node) { P ans = MP(INF,INF); for( ; p < san.size(); p += p&-p) { it = ss[p].lower_bound(node); if(it == ss[p].end()) continue; ans = min(ans, *it); } if(ans.first == INF) printf("-1\n"); else printf("%d %d\n", ans.first, ans.second); } int main() { scanf("%d", &n); char s[10]; for(int i = 0; i < n ; i ++) { scanf("%s%d%d", s, &q[i].x, &q[i].y); q[i].c = s[0]; san.push(q[i].y); } san.doit(); for(int i = 0; i < n; i ++) { if(q[i].c == 'a') add(san[q[i].y], MP(q[i].x,q[i].y)); else if(q[i].c == 'r') remove(san[q[i].y], MP(q[i].x, q[i].y)); else query(san[q[i].y]+1, MP(q[i].x+1, q[i].y+1)); } return 0; }