hdu2871 Memory Control 线段树,二分

之前在poj做过hotel题,看到这题时就想到是线段树了。但是这题比hotel多一些操作,这就让我捉急了。这里NEW操作相当于hotel中的入住,Free操作相当于退房,但是又有一点不同,每次给你一个地址,要求知道这个地址是否在使用,在使用的话是被哪个区间使用,在这个操作中借用的别人的想法,利用vector二分查找位置,GET操作由于引用的vector所以操作很简单,在Reset操作时不能重新建树,否则会超时, 要用update进行更新。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;

const int maxn = 50000+10;
struct ST {
      int l, r, lsum, rsum, sum, d;
}v[maxn<<2];
int n, m, data;
char s[11];

struct node {
      int s, e;
      node(int s, int e):s(s), e(e){}
};
bool cmp(const node &a, const node &b) {
      return a.s<b.s;//按开始的位置排序
}
vector<node> vc;
vector<node>::iterator it;

void build(int l, int r, int n) {
      v[n].l = l, v[n].r = r;
      v[n].lsum = v[n].rsum = v[n].sum = r-l+1;
      v[n].d = -1;
      if (l==r)
            return ;
      int mid = (v[n].l + v[n].r) >> 1;
      build (l, mid, n<<1);
      build(mid+1, r, n<<1|1);
}
inline void pushdown(int n) {
      if (v[n].d!=-1) {
            v[n<<1].d = v[n<<1|1].d = v[n].d;
            int len = (v[n].r-v[n].l+1);
            v[n<<1].lsum = v[n<<1].rsum = v[n<<1].sum = v[n].d==1?0:(len-(len>>1));
            v[n<<1|1].lsum = v[n<<1|1].rsum = v[n<<1|1].sum = v[n].d==1?0:(len>>1);
            v[n].d = -1;
      }
}
int query(int size, int n) {
      if (v[n].l==v[n].r)
            return v[n].l;
      int mid = (v[n].l + v[n].r) >> 1;
      pushdown(n);
      if (v[n<<1].sum>=size) {
            return  query(size, n<<1);
      } else if (v[n<<1].rsum+v[n<<1|1].lsum>=size) {
            return mid-v[n<<1].rsum+1;
      } else {
            return query(size, n<<1|1);
      }
}
inline int Max(int x, int y) {
      return x>y?x:y;
}
inline void pushup(int n) {
      v[n].lsum = v[n<<1].lsum;
      v[n].rsum = v[n<<1|1].rsum;
      int len = (v[n].r-v[n].l+1);
      if (v[n].lsum==(len-(len>>1)))
            v[n].lsum += v[n<<1|1].lsum;
      if (v[n].rsum==(len>>1))
            v[n].rsum += v[n<<1].rsum;
      v[n].sum = Max(v[n<<1].rsum+v[n<<1|1].lsum, Max(v[n<<1].sum, v[n<<1|1].sum));
}
void update(int l, int r, int d, int n) {
      if (l<=v[n].l && v[n].r<=r) {
            v[n].d = d;
            v[n].lsum = v[n].rsum = v[n].sum = d==1?0:(r-l+1);
            return ;
      }
      pushdown(n);
      int mid = (v[n].l + v[n].r) >> 1;
      if (r<=mid) {
            update(l, r, d, n<<1);
      } else if (l>mid) {
            update(l, r, d, n<<1|1);
      } else {
            update(l, mid, d, n<<1);
            update(mid+1, r, d, n<<1|1);
      }
      pushup(n);
}

int main()
{
      while (~scanf("%d%d", &n, &m)) {
            build(1, n, 1);
            vc.clear();
            while (m--) {
                  scanf("%s", s);
                  if (s[0]=='N') {
                        scanf("%d", &data);
                        if (v[1].sum<data || data<=0) {
                              printf("Reject New\n");
                        } else {
                              int idx = query(data, 1);
                              update(idx, idx+data-1, 1, 1);
                              printf("New at %d\n", idx);
                              node p(idx, idx+data-1);
                              it = upper_bound(vc.begin(), vc.end(), p, cmp);
                              vc.insert(it, p);//二分找到比p大的位置,在it之前插入p
                        }
                  } else if (s[0]=='F') {
                        scanf("%d", &data);
                        node p(data, data);
                        it = upper_bound(vc.begin(), vc.end(), p, cmp);
                        //二分p比大的位置,如果p在该位置的前一个位置为合法
                        int tmp = it-vc.begin()-1;
                        if (tmp==-1 || data<vc[tmp].s || data>vc[tmp].e) {
                              printf("Reject Free\n");
                        } else {
                              update(vc[tmp].s, vc[tmp].e, 0, 1);
                              printf("Free from %d to %d\n", vc[tmp].s, vc[tmp].e);
                              vc.erase(tmp+vc.begin());
                        }
                  } else if (s[0]=='G') {
                        scanf("%d", &data);
                        int tmp = vc.end()-vc.begin();
                        if (data>tmp || data<=0) {
                              printf("Reject Get\n");
                        } else {
                              printf("Get at %d\n", vc[data-1].s);
                        }
                  } else if (s[0]=='R') {
                        update(1, n, 0, 1);
                        printf("Reset Now\n");
                        vc.clear();
                  }
            }printf("\n");
      }
      return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值