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; }