zoukankan      html  css  js  c++  java
  • 【POJ3667】Hotel-线段树

    (本人本题完成于2016-7-22)

    题目大意:有一个旅馆有N个房间,标号为1,2,...,n,刚开始它们都是空着的。有M个操作,分为两种:1.找到标号最小的连续的D个房间并入住,并输出这些房间中标号最小的房间的标号,如果找不到这样的连续房间则输出0。2.清空从X号房间开始的D个房间。

    做法:建一棵线段树,除区间左右端点外维护:sum:该区间内的最大连续空区间长度。lsum:该区间的最左边的连续空区间长度。rsum:该区间的最右边的连续空区间长度。p:标记该区间是否全空(p=1)或全满(p=0),p=-1时表示没有标记。

    以下是本人代码:

    #include <cstdio>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    int n,m,o,a,x;
    struct node
    {
      int l,r;
      int lsum,rsum,sum,p;
    }seg[200010];
    
    void buildtree(int no,int l,int r) //建立线段树
    {
      int mid=(l+r)/2;
      seg[no].l=l;seg[no].r=r;
      seg[no].sum=seg[no].lsum=seg[no].rsum=r-l+1;
      seg[no].p=-1;
      if (l!=r)
      {
    	buildtree(2*no,l,mid);
    	buildtree(2*no+1,mid+1,r);
      }
    }
    
    void pushdown(int no) //将节点no的标记下放
    {
      if (seg[no].p!=-1)
      {
        seg[2*no].p=seg[2*no+1].p=seg[no].p;
        if (!seg[2*no].p)
    	{
    	  seg[2*no].lsum=seg[2*no].rsum=seg[2*no].sum=0;
    	  seg[2*no+1].lsum=seg[2*no+1].rsum=seg[2*no+1].sum=0;
    	}
    	else
    	{
    	  seg[2*no].lsum=seg[2*no].rsum=seg[2*no].sum=seg[2*no].r-seg[2*no].l+1;
    	  seg[2*no+1].lsum=seg[2*no+1].rsum=seg[2*no+1].sum=seg[2*no+1].r-seg[2*no+1].l+1;
    	}
    	seg[no].p=-1;
      }
    }
    
    void pushup(int no) //用更新后的no的儿子的数值来更新节点no
    {
      seg[no].lsum=seg[2*no].lsum;
      seg[no].rsum=seg[2*no+1].rsum;
      if (seg[2*no].lsum==seg[2*no].r-seg[2*no].l+1) seg[no].lsum+=seg[2*no+1].lsum;
      if (seg[2*no+1].rsum==seg[2*no+1].r-seg[2*no+1].l+1) seg[no].rsum+=seg[2*no].rsum;
      seg[no].sum=max(max(seg[2*no].sum,seg[2*no+1].sum),seg[2*no].rsum+seg[2*no+1].lsum);
    }
    
    int query(int no,int a) //查询并返回标号最小的长度为a的连续空区间的左端点标号
    {
      int mid=(seg[no].l+seg[no].r)/2;
      if (seg[no].l==seg[no].r) return seg[no].l;
      pushdown(no);
      if (seg[2*no].sum>=a) return query(2*no,a);
      if (seg[2*no].rsum+seg[2*no+1].lsum>=a) return mid-seg[2*no].rsum+1;
      if (seg[2*no+1].sum>=a) return query(2*no+1,a);
      return -1;
    }
    
    void checkin(int no,int s,int t) //将区间(s,t)覆盖
    {
      int mid=(seg[no].l+seg[no].r)/2;
      if (seg[no].l>=s&&seg[no].r<=t)
      {
        seg[no].lsum=seg[no].rsum=seg[no].sum=0;
    	seg[no].p=0;
    	return;
      }
      pushdown(no);
      if (s<=mid) checkin(2*no,s,t);
      if (t>mid) checkin(2*no+1,s,t);
      pushup(no);
    }
    
    void checkout(int no,int s,int t) //清空区间(s,t)
    {
      int mid=(seg[no].l+seg[no].r)/2;
      if (seg[no].l>=s&&seg[no].r<=t)
      {
        seg[no].lsum=seg[no].rsum=seg[no].sum=seg[no].r-seg[no].l+1;
    	seg[no].p=1;
        return;
      }
      pushdown(no);
      if (s<=mid) checkout(2*no,s,t);
      if (t>mid) checkout(2*no+1,s,t);
      pushup(no);
    }
    
    int main()
    {
      scanf("%d %d",&n,&m);
      buildtree(1,1,n);
      for(int i=1;i<=m;i++)
      {
        scanf("%d",&o);
    	if (o==1)
    	{
    	  scanf("%d",&a);
    	  if (seg[1].sum<a) printf("0
    "); //如果没有那么长的连续空区间,输出0
    	  else
    	  {
    	    int f=query(1,a);
    		printf("%d
    ",f);
    		checkin(1,f,f+a-1);
    	  }
    	}
    	if (o==2)
    	{
    	  scanf("%d %d",&a,&x);
    	  checkout(1,a,a+x-1);
    	}
      }
      
      return 0;
    }
    


  • 相关阅读:
    bugku细心地大象
    【学术篇】一些水的不行的dp
    【笔记篇】莫队算法(一)
    【学术篇】luogu1351 [NOIP2014提高组] 联合权值
    【学术篇】网络流24题——方格取数加强版
    【学术篇】SDOI2009 SuperGCD
    【学术篇】网络流24题——方格取数问题
    【模板篇】A* 寻路算法
    【模板篇】k短路 SDOI2010 魔法猪学院
    【学术篇】SDOI2009 最优图像
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9794010.html
Copyright © 2011-2022 走看看