hdu 5107 线段树+离散化+归并排序+极角排序

首先这道题的数据范围极大,那么一定是要离散化的,离散化就是读入之后,记录id,分别按照x和y排序,排序之后重新记录成连续的坐标

然后数据量也挺大,而且没有重点,所以直接极角排序,然后将横坐标映射到一棵线段树上,对y排序,然后逐渐将当前y坐标下的点更新到线段树中,在线的更新查询数对,然后另开一个数组记录答案.

对于线段树要维护的东西,其实就是因为k比较小,所以我们直接开10的数组,然后利用归并排序,这样就是可以在线段树上动态的更新每段上当前的有序前k大,所以最后答案可以进行o(1)的查询.

感觉我的算法比较清晰,一步一步来还是可以做的,但作为弱菜的我做了3个小时.......好伤感,还好1A.

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <algorithm>
#define MAX 30007

using namespace std;

int n,m;
struct Building
{
    int x,y,h;
    bool operator < ( const Building& a ) const
    {
        return y < a.y;
    }
}b[MAX];

struct Query 
{
    int x,y,k,id;
    bool operator < ( const Query& a ) const
    {
        return y < a.y;
    }
}q[MAX];

struct Discret
{
    int x , y ,id;
}d[MAX<<1];

bool cmp1 ( Discret d1 , Discret d2 )
{
    return d1.x < d2.x;
}

bool cmp2 ( Discret d1 , Discret d2 )
{
    return d1.y < d2.y;
}

struct Node
{
    int l,r,pre[12];
}tree[MAX<<2];

void push_up ( int u )
{
    int id1 = 1 , id2 = 1 , id = 1;
    while ( tree[u<<1].pre[id1]!= -1 && tree[u<<1|1].pre[id2] != -1 )
    {
        if ( id > 10 ) break;
        if ( tree[u<<1].pre[id1] < tree[u<<1|1].pre[id2] )
            tree[u].pre[id++] = tree[u<<1].pre[id1++];
        else tree[u].pre[id++] = tree[u<<1|1].pre[id2++];
    }
    while ( tree[u<<1].pre[id1] != -1 )
    {
        if ( id > 10 ) break;
        tree[u].pre[id++] = tree[u<<1].pre[id1++];
    }
    while ( tree[u<<1|1].pre[id2] != -1 )
    {
        if ( id > 10 ) break;
        tree[u].pre[id++] = tree[u<<1|1].pre[id2++];
    }
   // cout << "root  " << u <<" " <<tree[u].l << " " << tree[u].r<<  endl;
   // for ( int i = 1 ; i <= 10 ; i++ )
     //   cout << tree[u].pre[i] << " ";
   // cout << endl;
}

void build ( int u , int left , int right )
{
    memset ( tree[u].pre , -1 , sizeof ( tree[u].pre ) );
    tree[u].l = left , tree[u].r = right;
    if ( left == right ) return;
    int mid = left + right >>1;
    build ( u<<1 , left , mid );
    build ( u<<1|1 , mid+1 , right );
}

void update ( int u , int h , int x )
{
    int l = tree[u].l , r = tree[u].r;
    if ( l == r )
    {
        if ( tree[u].pre[1] == -1 ) tree[u].pre[1] = h;
        else 
        {
            int i;
            for ( i = 11 ; i >= 2 ; i++ )
            {
                if ( tree[u].pre[i-1] == -1 ) continue;
                if ( tree[u].pre[i] == -1 ) 
                    tree[u].pre[i] = h;
            }
            while ( tree[u].pre[i] < tree[u].pre[i-1] )
            {
                int temp = tree[u].pre[i];
                tree[u].pre[i] = tree[u].pre[i-1];
                tree[u].pre[i-1] = temp;
                i--;
            }
            tree[u].pre[11] = -1;
        }
        return;
    }
    int mid = l + r >> 1;
    if (  x >= l && x <= mid ) 
        update ( u<<1 , h , x );
    else 
        update ( u<<1|1 , h , x );
    push_up ( u );
}

struct Array
{
    int a[12];
    Array ( )
    {
        memset ( a , -1 , sizeof ( a ) );
    }
};

Array query ( int u , int left , int right )
{
    int l = tree[u].l , r = tree[u].r;
    int mid = l + r >> 1;
    Array ret; 
    if ( left <= l && r <= right )
    {
       /* cout << "______________________" << endl;
        cout << l << " " << r << " " << endl;
        for ( int i = 1 ; i <= 10 ; i++ )
            cout << tree[u].pre[i] << " ";
        cout << endl;
        cout << " ++++++++++++++++++++++" << endl;*/
        for ( int i = 1 ; i <= 10 ; i++ )
            ret.a[i] = tree[u].pre[i];
        return ret;
    }
    Array temp1 , temp2;
    if ( left <= mid && right >= l ) 
        temp1 = query ( u<<1 , left , right );
    if ( left <= right && right > mid )
        temp2 = query ( u<<1|1 , left , right );
    int id1 = 1 , id2 = 1 , id = 1;
    while ( temp1.a[id1] != -1 && temp2.a[id2] != -1 )
    {
        if ( id > 10 ) break;
        if ( temp1.a[id1] < temp2.a[id2] )
            ret.a[id++] = temp1.a[id1++];
        else ret.a[id++] = temp2.a[id2++];
    }
    while ( temp1.a[id1] != -1 )
    {
        if ( id > 10 ) break;
        ret.a[id++] = temp1.a[id1++];
    }
    while ( temp2.a[id2] != -1 )
    {
        if ( id > 10 ) break;
        ret.a[id++] = temp2.a[id2++];
    }
    return ret;   
}

int ans[MAX];

int main ( )
{
    while ( ~scanf ( "%d%d" , &n , &m ) )
    {
        for ( int i = 1 ; i <= n; i++ )
        {
            scanf ( "%d%d%d" , &d[i].x , &d[i].y, &b[i].h );
            d[i].id = i;
        }
        for ( int i = 1 ; i <= m ; i++ )
        {
            scanf ( "%d%d%d" , &d[i+n].x , &d[i+n].y , &q[i].k );
            d[i+n].id = i+n;
            q[i].id = i;
        }
        sort ( d+1 , d+n+m+1 , cmp1 );
        int cnt1 = 1 , cnt2 = 1;
        if ( d[1].id > n ) q[d[1].id-n].x = cnt1;
        else b[d[1].id].x = cnt1;
        for ( int i = 2 ; i <= n+m ; i++ )
        {
            if ( d[i].x != d[i-1].x ) cnt1++;
            if ( d[i].id > n ) q[d[i].id-n].x = cnt1;
            else b[d[i].id].x = cnt1;
        }
        sort ( d+1 , d+n+m+1 , cmp2 );
        if ( d[1].id > n ) q[d[1].id-n].y = cnt2;
        else b[d[1].id].y = cnt2;
        for ( int i = 2 ; i <= n+m ; i++ )
        {
            if ( d[i].y != d[i-1].y ) cnt2++;
            if ( d[i].id > n ) q[d[i].id-n].y = cnt2;
            else b[d[i].id].y = cnt2;
        }
        sort ( b+1 , b+n+1 );
        sort ( q+1 , q+m+1 );
        build ( 1 , 1 , cnt1 );
        int j = 1;
        for ( int i = 1 ; i <= m ; i++ )
        {
            int y = q[i].y;
            while ( b[j].y <= y )
            {
                update ( 1 , b[j].h , b[j].x );
               // cout << "Okay: " << j << " " << b[j].h << " " << b[j].x << endl;
                if ( j >= n ) break;
                j++;
            }
            Array record = query ( 1 , 1 , q[i].x );
          /*  cout << "Id : " << q[i].id << " " << q[i].x << endl;
            for ( int t = 1 ; t <= 10 ; t++ )
                cout << record.a[t] << " ";
            cout << endl;*/
            ans[q[i].id] = record.a[q[i].k];
        }
        for ( int i = 1 ; i <= m ; i++ )
            printf ( "%d\n" , ans[i] );
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值