HDU 5107

是一道线段树的离线操作,感觉这种类型的题第一次碰到,比赛的时候对这个完全没赶脚,没有把问题想全面就开始做,以至于忽视了很多问题。然后后来看了题解,又纠结了几天发现自己把题意理解的有点错,我以为是对于每个区间,1th,2th的高度一定要不一样,所以一直有放着去重,然后就果断华丽丽的T了好多发……还死命觉得别人用了一种非常巧妙的方法不用每次都去重也能进行这样的去重筛选……

然后我觉得……我的debug能力真的很差……

听说什么样的人就会有什么样的代码……

所以……

好吧……不要在意这些细节……为什么会Tle……!!!还有RE

先说下思路把,我觉得这样用很巧。把查询和放置都放在一起,然后进行排序,排序得很好,先排X,再排Y,再按操作的类型排序,先是放置的,再是查询的。这样做有一个好处,当你建树的时候,先把楼给放在坐标上,然后查询的时候可以省略X的坐标,因为在你现在查询的时候,所存在的X肯定实在你的查询范围内的(排序!!)然后就每个节点存储每次在同Y轴的楼的高度,然后向上更新,如果存的节点大于十,就排序下,然后取10。


然后这次get了离散化的方法……(终于)

先放个RE的代码……QAQ

***************************************

居然WA掉了…………嘤嘤,RE是因为线段树开小了,学别人开了8倍……开4倍貌似就不行,但是好像有的时候会说是T,有的时候是MLE,有的时候是WA……

好心累……检查了好多天的代码……

#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <map>

using namespace std;
#define maxn 30030
map<int,int>mp;
struct node
{
    int x,y,z;
    int id,op;
}lou[maxn<<1];
struct nodee
{
    int a[30];
    int num;
}tree[maxn<<2];
int ans[100];
int y[maxn<<2];
int top;
int tot[maxn];
int cmp(node a,node b)
{
    if(a.x!=b.x) return a.x<b.x;
    else if(a.y!=b.y) return a.y<b.y;
    return a.op<b.op;
}
void creat(int l,int r,int rt)
{
    tree[rt].num=0;
    if(l==r) return;
    int mid=(l+r)/2;
    creat(l,mid,rt<<1);
    creat(mid+1,r,rt<<1|1);
}
void sum(int rt)
{
    int l,r;
    int i;
    l=tree[rt<<1].num;r=tree[rt<<1|1].num;
    int tmp[22];
    for(i=1;i<=l;i++) tmp[i]=tree[rt<<1].a[i];
    for(i=1;i<=r;i++) tmp[i+l]=tree[rt<<1|1].a[i];
    sort(tmp+1,tmp+1+l+r);
    if(l+r>10) tree[rt].num=10;
    else tree[rt].num=l+r;
    for(i=1;i<=tree[rt].num;i++) tree[rt].a[i]=tmp[i];
}
void del(int rt)
{
    sort(tree[rt].a+1,tree[rt].a+tree[rt].num+1);
    tree[rt].num=10;
}
void update(int pos,int h,int l,int r,int rt)
{
    if(l==pos&&r==pos)
    {
        tree[rt].a[++tree[rt].num]=h;
        if(tree[rt].num>10) del(rt);
        return;
    }
    int mid=(l+r)/2;
    if(pos<=mid) update(pos,h,l,mid,rt<<1);
    else update(pos,h,mid+1,r,rt<<1|1);

    sum(rt);
}
void query(int ll,int rr,int l,int r,int rt)
{
    if(l==ll&&r==rr)
    {
        for(int i=1;i<=tree[rt].num;i++)
            ans[++top]=tree[rt].a[i];
        if(top>10)
        {
            sort(ans+1,ans+1+top);
            top=10;
        }
        return;
    }
    int mid=(l+r)/2;
    if(rr<=mid) query(ll,rr,l,mid,rt<<1);
    else if(ll>mid) query(ll,rr,mid+1,r,rt<<1|1);
    else {query(ll,mid,l,mid,rt<<1),query(mid+1,rr,mid+1,r,rt<<1|1);}
}
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int i,j,k;
        for(i=1;i<=n;i++)
        {
            scanf("%d%d%d",&lou[i].x,&lou[i].y,&lou[i].z);
            y[i]=lou[i].y;
            lou[i].op=1;
        }
        for(i=n+1;i<=n+m;i++)
        {
            scanf("%d%d%d",&lou[i].x,&lou[i].y,&lou[i].z);
            y[i]=lou[i].y;
            lou[i].op=2;
            lou[i].id=i-n;
        }
        int cnt=n+m;
        sort(y+1,y+1+cnt);
        int tmp=unique(y+1,y+1+cnt)-y-1;
        for(i=1;i<=tmp;i++)
            mp[y[i]]=i;
        creat(1,tmp,1);
        sort(lou+1,lou+1+cnt,cmp);
        for(i=1;i<=cnt;i++)
        {
            if(lou[i].op==1) update(mp[lou[i].y],lou[i].z,1,tmp,1);
            else
            {
                top=0;
                query(1,mp[lou[i].y],1,tmp,1);
                if(top<lou[i].z) tot[lou[i].id]=-1;
                else tot[lou[i].id]=ans[lou[i].z];
            }
        }
        for(i=1;i<=m;i++)
            printf("%d\n",tot[i]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值