bzoj2928: [Poi1999]飞弹

惨啊…… 被卡常是一种什么感受&……

 

很明显的分治。

我们首先可以找到所有点中的最低点,然后对所有点进行一次极角排序,选取一个点使得他各侧飞弹和地堡一样多,并对两侧继续进行分治。

很容易证明这样做的正确性。

然而这样做是\(n^{2}log(n)\)。所以我们需要加些玄学的优化……比如通过增加每次分治的宽度,以减少排序的次数……

 

……总之就是水过啦QAQ

#include <bits/stdc++.h>
#define N 20010
 
const int H = 600000;
char s0[H] , * s1 = s0 , * s2 = s1;
#define I ( s1 == s2 &&( s2 = ( s1 = s0 ) + fread( s0 , 1 , H , stdin ) , s1 == s2 ) ? 32 : * s1++ )
inline int read()
{
    register int x = 0 , c, f = 0;
    while( isspace( c = I ) );
    if (c == '-') f = 1; else x = x * 10 + c - 48;
    while(isdigit( c = I ) ) x = x * 10 + c - 48;
    return (f? -x: x);
}
 
using namespace std;
int n;
struct node
{
    int x, y, t, i;
} L[N];
node O;
int ansi[N];
int ci[N];
 
int compc(int a, int b)
{
    return ((L[a].x - O.x) * (L[b].y - O.y) - (L[b].x - O.x) * (L[a].y - O.y)) < 0;
}
int comp(node a, node b)
{
    return ((a.x - O.x) * (b.y - O.y) - (b.x - O.x) * (a.y - O.y)) < 0;
}
void solve(int l, int r)
{
    if (l > r) return;
    for (int i = l + 1; i <= r; ++ i)
        if (L[ci[i]].y < L[ci[l]].y) swap(ci[i], ci[l]);
    O = L[ci[l]];
    sort(ci + l + 1, ci + r + 1, compc);
    int np = l + 1;
    for (int i = l + 1, k = 0; i < r; ++ i)
    {
        k += L[ci[i]].t;
        if (k == 0)
        {
            solve(np, i);
            np = i + 1;
        }
    }
    if (L[ci[l]].t > 0) ansi[L[ci[l]].i] = L[ci[np]].i;
    else ansi[L[ci[np]].i] = L[ci[l]].i;
    solve(np + 1, r);
}
int compi(node a, node b)
{
    if (a.t != b.t) return a.t > b.t;
    else return a.i < b.i;
}
int checker()
{
    sort(L + 1, L + n * 2 + 1, compi);
    for (int i = 1; i <= n; ++ i)
        for (int j = 1; j <= n; ++ j)
            if (i != j)
            {
                O = L[i];
                int a = comp(L[ansi[i] + n], L[j]) ^ comp(L[ansi[i] + n], L[ansi[j] + n]);
                O = L[j];
                int b = comp(L[ansi[j] + n], L[i]) ^ comp(L[ansi[j] + n], L[ansi[i] + n]);
                if (a && b)
                    return 1;
            }
    return 0;
}
int main()
{
    //freopen("rak0.in", "r", stdin);
    n = read();
    for (int i = 1; i <= 2 * n; ++ i) ci[i] = i;
    for (int i = 1; i <= n; ++ i)
    {
        L[i].x = read(); L[i].y = read();
        L[i].t = 1; L[i].i = i;
    }
    for (int i = 1; i <= n; ++ i)
    {
        L[i + n].x = read(); L[i + n].y = read();
        L[i + n].t = -1; L[i + n].i = i;
    }
    solve(1, n * 2);
    for (int i = 1; i <= n; ++ i) printf("%d\n", ansi[i]);
    //printf("%d", checker());
}

 

posted @ 2016-08-30 15:23  AwD!  阅读(448)  评论(0编辑  收藏  举报