题意: 在一个二维平面上有10W个点,现在给你9个数,希望你用两根横线,两根竖线,将平面划分成9块,并且9个块的值对应那9个数。9个数可以任意排列。
解法: 我们枚举每一个排列,检验这个排列下对应的划分是否可行。由于数据范围,需要使用树套树的方法,这里使用树状数组套Treap来统计矩阵内的点数。
一般二叉树可以解决一维上的统计问题,但是当维度增加到二维时,一维的树显然不能满足需求,这时就需要用一棵树先将问题化简为一维,然后再用另一棵树来统计,比如这题就是用树状数组将平面上的点划分成矩形,然后将每个矩形内的点看做在一维直线上,然后用Treap统计。选用树状数组,显然比其他树有更低的编程复杂度。
/* **********************************************
Author : Nero
Created Time: 2013/9/2 19:01:57
Problem id : CF-158E
Problem Name: Dividing Kingdom
*********************************************** */
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <time.h>
#include <stdlib.h>
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))
const int MAXN = 101000;
const int INF = 0x3f3f3f3f;
// 离散化
struct San {
int a[MAXN], n;
void init() { n = 0; }
int size() { return n; }
void push(int x) { a[++n] = x; }
void doit() { sort(a+1,a+n+1); n = unique(a+1,a+n+1) - a-1; }
int operator [] (int x) { return lower_bound(a+1,a+n+1,x) - a; }
}sx,sy;
// 大根堆Treap
struct Node {
Node* ch[2];
int v,cnt,r,size;
int cmp(int x) {
if(x == v) return -1;
return x < v ? 0 : 1;
}
void up() { cnt = ch[0]->cnt + ch[1]->cnt + size; }
}*t[MAXN], *nill;
void init() {
srand(time(NULL));
nill = new Node();
nill->ch[0] = nill->ch[1] = nill;
nill->v = INF;
nill->cnt = nill->size = 0;
nill->r = rand();
for(int i = 0; i < MAXN; i ++) t[i] = nill;
}
void New_node(Node* &o, int x) {
o = new Node();
o->ch[0] = o->ch[1] = nill;
o->v = x;
o->cnt = o->size = 1;
o->r = rand();
}
void rotate(Node* &o, int d) {
Node* temp = o;
o = o->ch[d^1];
temp->ch[d^1] = o->ch[d];
o->ch[d] = temp;
o->ch[d]->up();
o->up();
}
void insert(Node* &o, int x) {
if(o == nill) {
New_node(o,x);
return ;
}
int d = o->cmp(x);
if(d == -1) {
o->cnt ++;
o->size ++;
} else {
insert(o->ch[d], x);
o->up();
if(o->ch[d]->r > o->r) rotate(o,d^1);
}
}
int Count(Node* o, int x) {
int ret = 0;
while(o != nill) {
int d = o->cmp(x);
if(d == 1) {
ret += o->size + o->ch[0]->cnt;
o = o->ch[1];
} else if(d == -1) {
ret += o->size + o->ch[0]->cnt;
break;
} else {
o = o->ch[0];
}
}
return ret;
}
void add(int p, int val) {
for( ; p <= sx.size(); p += p&-p) insert(t[p], val);
}
int Count(int p, int y) {
int ret = 0;
for( ; p > 0; p -= p&-p) ret += Count(t[p], y);
return ret ;
}
struct Point {
int x,y;
}po[MAXN];
int n;
int cc[9];
int x1,x2,y1,y2;
Point px[MAXN],py[MAXN];
bool by_x(Point a, Point b) {
if(a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
bool by_y(Point a, Point b) {
if(a.y == b.y) return a.x < b.x;
return a.y < b.y;
}
bool Solve() {
int sum;
sort(cc,cc+9);
do {
sum = cc[0] + cc[1] + cc[2];
if(px[sum-1].x == px[sum].x) continue;
x1 = sx[px[sum-1].x];
sum += cc[3] + cc[4] + cc[5];
if(px[sum-1].x == px[sum].x) continue;
x2 = sx[px[sum-1].x];
sum = cc[0] + cc[3] + cc[6];
if(py[sum-1].y == py[sum].y) continue;
y1 = sy[py[sum-1].y];
sum += cc[1] + cc[4] + cc[7];
if(py[sum-1].y == py[sum].y) continue;
y2 = sy[py[sum-1].y];
if(Count(x1,y1) != cc[0]) continue;
if(Count(x2,y1) != cc[0] + cc[3]) continue;
if(Count(x1,y2) != cc[0] + cc[1]) continue;
if(Count(x2,y2) != cc[0] + cc[1] + cc[3] + cc[4]) continue;
return 1;
}while(next_permutation(cc,cc+9));
return 0;
}
int main() {
scanf("%d", &n);
for(int i = 0; i < n; i ++) {
scanf("%d%d", &po[i].x, &po[i].y);
px[i] = po[i];
py[i] = po[i];
sx.push(po[i].x);
sy.push(po[i].y);
}
sx.doit();
sy.doit();
sort(px,px+n,by_x);
sort(py,py+n,by_y);
init();
for(int i = 0; i < n; i ++) {
add(sx[po[i].x], sy[po[i].y]);
}
for(int i = 0; i < 9; i ++) scanf("%d", &cc[i]);
if(Solve()) {
printf("%lf %lf\n", 0.5+sx.a[x1], 0.5+sx.a[x2]);
printf("%lf %lf\n", 0.5+sy.a[y1], 0.5+sy.a[y2]);
} else {
printf("-1\n");
}
return 0;
}