POJ3667(线段树区间合并)

题意:给你1到n的区间,初始都能使用,两种操作:

1 x :找到最左端的能使用的长度为x的子区间,并使占用这个子区间; 2 x k :使得从x开始长度为k的子区间又能够使用。

线段树节点维护从左边开始的最长子区间,从右边开始的最长子区间,总的最长子区间,设三个节点为空标记,全满标记,和有隔断点标记,然后合并区间就很容易了。

 

#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define maxn 51111
#define maxm 8111111
#define pl c<<1
#define pr (c<<1)|1
#define lson tree[c].l,tree[c].mid,c<<1
#define rson tree[c].mid+1,tree[c].r,(c<<1)|1
#define empty Empty
#define clear Clear
#define insert Insert

int n, m;
struct node {
    int l, r, mid;
    int Max, numl, numr;
    bool is; //是否分割
    bool full; //是否为满
    bool empty; //是否为空
}tree[maxn<<4];

void pushup (int c) {
    if (tree[c].l == tree[c].r)
        return ;
    if (!tree[pl].is) {
        tree[c].numl = tree[pl].Max+tree[pr].numl;
    }
    else tree[c].numl = tree[pl].numl;
    if (!tree[pr].is) {
        tree[c].numr = tree[pr].Max+tree[pl].numr;
    }
    else tree[c].numr = tree[pr].numr;
    tree[c].Max = max (tree[pl].numr+tree[pr].numl, max (tree[pl].Max, tree[pr].Max));
    tree[c].full = (tree[pl].full&tree[pr].full);
    tree[c].is = (tree[pl].is|tree[pr].is);
    tree[c].empty = (tree[pl].empty&tree[pr].empty);
}

void build_tree (int l, int r, int c) {
    tree[c].l = l, tree[c].r = r, tree[c].mid = (l+r)>>1;
    if (l == r) {
        tree[c].Max = tree[c].numl = tree[c].numr = 1;
        tree[c].is = 0;
        tree[c].full = 1;
        tree[c].empty = 0;
        return ;
    }
    build_tree (lson);
    build_tree (rson);
    pushup (c);
}

void push_down_empty (int c) {
    tree[pl].Max = tree[pr].Max = tree[pl].numl = tree[pr].numl =
        tree[pl].numr = tree[pr].numr = 0;
    tree[pl].empty = tree[pr].empty = 1;
    tree[pl].is = tree[pr].is = 1;
    tree[pl].full = tree[pr].full = 0;
    return ;
}

void push_down (int c) {
    if (tree[c].l == tree[c].r)
        return ;
    if (tree[c].empty) {
        push_down_empty (c);
        tree[c].empty = 0;
    }
    if (tree[c].full) {
        tree[pl].numl = tree[pl].numr = tree[pl].Max = (tree[pl].r-tree[pl].l+1);
        tree[pr].numl = tree[pr].numr = tree[pr].Max = (tree[pr].r-tree[pr].l+1);
        tree[pl].empty = tree[pr].empty = 0;
        tree[pl].full = tree[pr].full = 1;
        tree[pl].is = tree[pr].is = 0;
    }
}

void clear (int l, int r, int c, int x, int y) {
    if (tree[c].empty || tree[c].full)
        push_down (c);
    if (l == x && y == r) {
        tree[c].numl = tree[c].numr = tree[c].Max = r-l+1;
        tree[c].full = 1;
        tree[c].is = 0;
        tree[c].empty = 0;
        return ;
    }
    else if (tree[c].mid >= y) {
        clear (lson, x, y);
    }
    else if (tree[c].mid < x) {
        clear (rson, x, y);
    }
    else {
        clear (lson, x, tree[c].mid);
        clear (rson, tree[c].mid+1, y);
    }
    pushup (c);
}

int query (int l, int r, int c, int len) {
    if (tree[c].empty || tree[c].full)
        push_down (c);
    if (tree[c].Max < len)
        return 0; //无解
    if (tree[pl].Max >= len)
        return query (lson, len);
    else if (tree[pl].numr + tree[pr].numl >= len) {
        return tree[c].mid-tree[pl].numr+1;
    }
    else return query (rson, len);
}

void insert (int l, int r, int c, int x, int y) {
    if (tree[c].full)
        push_down (c);
    if (l == x && r == y) {
        tree[c].empty = 1;
        tree[c].full = 0;
        tree[c].is = 1;
        tree[c].Max = tree[c].numl = tree[c].numr = 0;
        return ;
    }
    else if (tree[c].mid >= y) {
        insert (lson, x, y);
    }
    else if (tree[c].mid < x) {
        insert (rson, x, y);
    }
    else {
        insert (lson, x, tree[c].mid);
        insert (rson, tree[c].mid+1, y);
    }
    pushup (c);
}

void debug (int l, int r, int c) {
    cout << "l:" << l << " r:" << r << " max:" << tree[c].Max
    << " numl:" << tree[c].numl << " numr:" << tree[c].numr << endl;
    if (l == r)
        return ;
    debug (lson);
    debug (rson);
}

int main () {
    while (scanf ("%d%d", &n, &m) == 2) {
        build_tree (1, n, 1);
        for (int i = 1; i <= m; i++) {
            int op;
            scanf ("%d", &op);
            if (op == 1) {
                int k;
                scanf ("%d", &k);
                int pos = query (1, n, 1, k);
                printf ("%d\n", pos);
                if (pos) {
                    insert (1, n, 1, pos, pos+k-1);
                }
            }
            else if (op == 2) {
                int l, r;
                scanf ("%d%d", &l, &r);
                clear (1, n, 1, l, l+r-1);
            }
            //int tt; cin >>tt; if (tt == 100) debug (1, n, 1);
        }
    }
    return 0;
}

你可能感兴趣的:(POJ3667(线段树区间合并))