CF-260E Dividing Kingdom (树套树)

本文详细阐述了如何通过枚举排列并使用树状数组和Treap来解决二维平面上点的划分问题,具体介绍了离散化、大根堆Treap结构及其在二维统计问题中的应用。

题意: 在一个二维平面上有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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值