Hotel POJ - 3667(线段树 + 区间合并

题意: 给定长度为n的区间 ,有2个操作:

操作1: 在区间中靠左放k个元素,输出新放入元素中最左边的位置,如果放不下输出 0;

操作2 : 清空 l 到 l+w-1这一段区间的元素

 

这里有一个状态转移方程(即线段树的上推方式):

线段树区间pos中储存  lcon--从区间左端L最大连续的区间长度 , rcon--从线段树右端R最大连续的区间长度 ,mcon 区间内最大的区间长度

则:      t[pos].mcon = max{ t[Lpos].rcon+t[Rpos].lcon  ,t[Lpos].mcon  ,t[Rpos].mcon );

             t[pos].lcon = t[Lpos].lcon+(t[Rpos],lcon);  t[pos].rcon = t[Rpos].rcon+(t[Lpos].rcon) (如果左或右区间整段连续,就加上括号里面的部分

 

lazy标记的下移(对整段空或整段满的区间进行标记):

void pushdown( int L ,int R, int pos){
    if( t[pos].tag!=0 && t[pos].tag!=1 ) return ;
    int Mid;
     t[posl].tag = t[posr].tag =t[pos].tag;
     t[posl].mcon = t[posl].lcon = t[posl].rcon = t[pos].tag ? mid - L+1 : 0 ;
     t[posr].mcon = t[posr].lcon = t[posr].rcon = t[pos].tag ? R-mid : 0 ;
     t[pos].tag = -1;
     return ;
}

 

查询:

判断能否放下: 比较k与总区间最大连续区间长度t[ 1 ].mcon 的大小

查询新放入元素最左坐标:如果左区间最大连续空区间大于目标长度就一直查询左区间,直到查询不了就判断左区间右连续加上右区间左连续可不可以,可以就输出结果,不行的话在查询右区间                                                                

int query(  int L ,int R ,int pos ,int w ){
     if( L==R ) return L;
    // cout<< L <<' '<<R << ' '<<w<<endl;
     pushdown( L ,R ,pos);
     int Mid;
     if( t[posl].mcon >= w ) return query( lson , w);                                           //优先查左边
     else if( t[posl].rcon + t[posr].lcon >= w) return mid - t[posl].rcon +1 ; //查到左边放不下了,输出区间放在中间的结果
     else return query( rson ,w);                                                                            //中间放不了,最末查询右边
}

更新比较平常 ,就不说了

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define posl pos<<1
#define posr pos<<1|1
#define lson L ,mid ,posl
#define rson mid+1 ,R ,posr
#define Mid mid=(L+R)>>1

struct tree{
     int lcon ,rcon ,mcon;
     int  tag;
} t[50005<<2];
void pushup( int L ,int R ,int pos){
     t[pos].lcon = t[posl].lcon;
     t[pos].rcon = t[posr].rcon;
     int Mid;
     if( t[pos].lcon == mid - L +1 ) t[pos].lcon += t[posr].lcon;
     if( t[pos].rcon == R - mid ) t[pos].rcon += t[posl].rcon;
     t[pos].mcon = max( t[posl].rcon+t[posr].lcon ,max( t[posl].mcon  ,t[posr].mcon));
}

void pushdown( int L ,int R, int pos){
    if( t[pos].tag!=0 && t[pos].tag!=1 ) return ;
    int Mid;
     t[posl].tag = t[posr].tag =t[pos].tag;
     t[posl].mcon = t[posl].lcon = t[posl].rcon = t[pos].tag ? mid - L+1 : 0 ;
     t[posr].mcon = t[posr].lcon = t[posr].rcon = t[pos].tag ? R-mid : 0 ;
     t[pos].tag = -1;
     return ;
}

void build( int L ,int R ,int pos){
     t[pos].tag = -1;
     t[pos].lcon = t[pos].rcon = t[pos].mcon = R - L +1;
     if( L == R) return ;
     int Mid;
     build( lson);
     build( rson);
}

void updata( int L ,int R ,int pos ,int l,int r,int v ){
     if( L>= l && R <= r ){

        t[pos].mcon = t[pos].rcon = t[pos].lcon = v ? R - L +1 : 0 ;
        t[pos].tag = v;
        return ;
     }
     if( L == R)return;
     pushdown( L ,R ,pos);
     int Mid;
     if( l <= mid ) updata( lson ,l ,r ,v);
     if( mid < r) updata( rson ,l ,r ,v);
     pushup( L ,R ,pos);
}

int query(  int L ,int R ,int pos ,int w ){
     if( L==R ) return L;
    // cout<< L <<' '<<R << ' '<<w<<endl;
     pushdown( L ,R ,pos);
     int Mid;
     if( t[posl].mcon >= w ) return query( lson , w);                                           //优先查左边
     else if( t[posl].rcon + t[posr].lcon >= w) return mid - t[posl].rcon +1 ; //查到左边放不下了,输出区间放在中间的结果
     else return query( rson ,w);                                                                            //中间放不了,最末查询右边
}
int main( ){
     int n,m;
     scanf( "%d%d" ,&n ,&m);
     build( 1 ,n ,1);
     while( m-- ){
         int op ,k ,l ,r;
         scanf("%d" ,&op);
         if( op ==1){
             scanf("%d" ,&k);
             if( t[1].mcon >=k){
                 l=query( 1 ,n ,1 ,k);
                 updata( 1 , n ,1 ,l ,l+k-1, 0);
                 printf("%d\n" ,l);
             }
             else printf("0\n");
         }
         else{
             scanf("%d%d",&l ,&r);
             updata( 1 ,n ,1 ,l ,l+r-1,1);
         }
     }
     return 0;
}
posted @ 2019-03-31 18:19  易如鱼  阅读(285)  评论(0编辑  收藏  举报