HDU-2871:Memory Control(区间合并+vector二分)


题目链接:点击打开链接


题目大意:

有一个长为n的空序列,有4种操作,

(1)  找到一个连续长为x的空序列,将其覆盖(尽量靠左),并输出覆盖的起点坐标

(2)  将包含x的那个块所在的序列重新清空,并输出free的起点和终点

(3)  得到序列中第x个块的起点,

(4)  将整个序列清空,


解题思路:

刚开始完全是蒙蔽的,其实第一个操作还很好说,就是跟一道名为 Hotel(POJ 3667) 的题差不多,但是操作 2 ,3 那是完全不会。想了几天,还是不知道怎么实现。

后来碰到一道扫描线的题目,想了想,好难啊,还是回头做这一道吧,然后考虑到每次他让你新建和删除的块是可以用数组记录下来的,就试了一下,果然可行,然后就 t 掉了。真的不会了,然后去网上找大佬的代码看,发现大佬用的二分+vector,我用数组在插入块那个地方是直接 sort ,不断的sort实在耗时,不过这 stl 更tm神奇,以前从来不知道vector还有这么多操作。插入 删除 反正vector都能实现,注意二分找位置就好,还有清空全部那个地方不要用 build 初始化,耗时,用 update 正常更新就行。细节看代码


#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
#define hash haha
using namespace std;
typedef long long ll;
int n,m;
char c[10];
struct nodes    //vector的元素
{
    int x,y;
};
vector<nodes> a;
bool cmp(const nodes &a,const nodes &b)
{
    return a.x<b.x;
}
struct node
{
    int l,r,mid;    //记录左最长右最长和区间最长
    int ls,rs,ms;   //是否覆盖的标记和延迟标记
    int cnt,lazy;
}t[200000];
void pushdown(int rt)      //正常的区间合并pushdown
{
    if(t[rt].lazy)
    {
        if(t[rt].cnt)
        {
            t[lson].ls=t[lson].rs=t[lson].ms=0;
            t[rson].ls=t[rson].rs=t[rson].ms=0;
        }
        if(!t[rt].cnt)
        {
            t[lson].ls=t[lson].rs=t[lson].ms=t[lson].r-t[lson].l+1;
            t[rson].ls=t[rson].rs=t[rson].ms=t[rson].r-t[rson].l+1;
        }
        t[lson].lazy=t[rson].lazy=t[rt].lazy;
        t[lson].cnt=t[rson].cnt=t[rt].cnt;
        t[rt].lazy=t[rt].cnt=0;
    }
}
void pushup(int rt)     //同上
{
    if(t[lson].ls==t[lson].r-t[lson].l+1)
        t[rt].ls=t[lson].ls+t[rson].ls;
    else
        t[rt].ls=t[lson].ls;
    if(t[rson].rs==t[rson].r-t[rson].l+1)
        t[rt].rs=t[lson].rs+t[rson].rs;
    else
        t[rt].rs=t[rson].rs;
    t[rt].ms=max(max(t[lson].ms,t[rson].ms),t[lson].rs+t[rson].ls);
}
void build(int l,int r,int rt)
{
    int mid=(l+r)>>1;
    t[rt].l=l;t[rt].r=r;
    t[rt].mid=mid;
    t[rt].cnt=0;t[rt].lazy=0;
    t[rt].ls=t[rt].rs=t[rt].ms=0;
    if(l==r)
    {
        t[rt].ls=t[rt].rs=t[rt].ms=1;
        return ;
    }
    build(l,mid,lson);
    build(mid+1,r,rson);
    pushup(rt);
}
void update(int l,int r,int flag,int rt)    //正常的更新
{
    if(l<=t[rt].l&&t[rt].r<=r)
    {
        t[rt].lazy=1;
        t[rt].cnt=flag;
        if(t[rt].cnt)
            t[rt].ls=t[rt].rs=t[rt].ms=0;
        else
            t[rt].ls=t[rt].rs=t[rt].ms=t[rt].r-t[rt].l+1;
        return ;
    }
    pushdown(rt);
    if(l<=t[rt].mid)
        update(l,r,flag,lson);
    if(r>t[rt].mid)
        update(l,r,flag,rson);
    pushup(rt);
}
int query(int k,int rt)         //查询满足最长连续区间的左端点
{
    if(t[rt].l==t[rt].r)
        return 1;
    pushdown(rt);
    if(t[lson].ms>=k)
        return query(k,lson);
    else if(t[lson].rs+t[rson].ls>=k)
        return t[rt].mid-t[lson].rs+1;
    else if(t[rson].ms>=k)
        return query(k,rson);
    pushup(rt);
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,n,1);
        a.clear();      //初始化vector
        while(m--)
        {
            int q;
            scanf(" %s",c);
            if(c[0]=='N')
            {
                scanf("%d",&q);
                if(t[1].ms>=q)
                {
                    int st=query(q,1);
                    nodes k;
                    k.x=st;
                    k.y=st+q-1;
                    vector<nodes>::iterator it;     //神奇的vector二分,不会,stl还是学的太烂了
                    it=upper_bound(a.begin(),a.end(),k,cmp);
                    a.insert(it,k);         //找到位置然后插入
                    update(st,st+q-1,1,1);          //更新
                    printf("New at %d\n",st);
                }
                else
                    printf("Reject New\n");
            }
            if(c[0]=='F')
            {
                scanf("%d",&q);
                nodes k;
                k.x=q;
                k.y=q;
                vector<nodes>::iterator it;
                it=upper_bound(a.begin(),a.end(),k,cmp);    //二分查找
                int tmp=it-a.begin()-1;
                if(tmp==-1||a[tmp].y<q)         //如果没找到
                    printf("Reject Free\n");
                else
                {
                    update(a[tmp].x,a[tmp].y,0,1);      //找到的话更新删除
                    printf("Free from %d to %d\n",a[tmp].x,a[tmp].y);
                    a.erase(a.begin()+tmp);
                }
            }
            if(c[0]=='G')
            {
                scanf("%d",&q);
                if(q<=(int)a.size())    //看是否有这么多元素
                    printf("Get at %d\n",a[q-1].x);
                else
                    printf("Reject Get\n");
            }
            if(c[0]=='R')
            {
                a.clear();  //初始化队列
                update(1,n,0,1);
                printf("Reset Now\n");
            }
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值