码迷,mamicode.com
首页 > 其他好文 > 详细

poj 3667(线段树 区间合并) 开房吧

时间:2015-08-14 11:28:08      阅读:134      评论:0      收藏:0      [点我收藏+]

标签:

http://poj.org/problem?id=3667

宾馆有n个房间编号1到n都为空房,然后m个询问,当输入第一个为1的时候,代表要住进x个连续的房间,输入房间号最小的数,如果没有

输出0.当第一个数为2的时候,将从x号到y号的房间又变为空房,没有输出

与区间有关想想用线段树可不可以解决,就像是涂颜色一样把住与未住的房间号做个标记就行,问题是这里给的是区间的长度,并不是

具体的区间,处理起来比较麻烦 还要去找合适的区间,所以引入了len1表示某区间可用的最大长度,len2表示从区间左端开始可用的最大长度,

len3表示从区间右端开始可用的最大长度,最后更新维护一下

 

code

  1 #include<iostream>
  2 #include<cstdio>
  3 using namespace std;
  4 struct point {
  5     int l,r;
  6     int len1,len2,len3; 
  7     int mark; //lazy判断
  8 };
  9 point tree[50001*4];
 10 void build(int i,int left,int right)
 11 {
 12     tree[i].l=left,tree[i].r=right;
 13     tree[i].len1=tree[i].len2=tree[i].len3=tree[i].r-tree[i].l+1;//长度开始都为区间长度
 14     tree[i].mark=0;
 15     if (left==right) return;
 16     int mid=(left+right)/2;
 17     build(i*2,left,mid);
 18     build(i*2+1,mid+1,right);
 19 }
 20 void update(int i,int left,int right,int val)
 21 {
 22     if (tree[i].l==left&&tree[i].r==right)
 23     {
 24         int e;
 25         tree[i].mark=val;
 26         if (val) e=0; //如果占领了,区间长度就为0了
 27         else e=tree[i].r-tree[i].l+1;
 28         tree[i].len1=tree[i].len2=tree[i].len3=e;
 29         return;
 30     }
 31     if (tree[i].mark!=-1)
 32     {
 33         int q=tree[i].mark,e,r;
 34         tree[i*2].mark=tree[i*2+1].mark=tree[i].mark;
 35         tree[i].mark=-1;
 36         if (q) e=0,r=0;
 37         else
 38         {
 39             e=tree[i*2].r-tree[i*2].l+1;
 40             r=tree[i*2+1].r-tree[i*2+1].l+1;
 41         }
 42         tree[i*2].len1=tree[i*2].len2=tree[i*2].len3=e;
 43         tree[i*2+1].len1=tree[i*2+1].len2=tree[i*2+1].len3=r;
 44     }
 45     int mid=(tree[i].r+tree[i].l)/2;
 46     if(left>mid) update(i*2+1,left,right,val);
 47     else if(right<=mid) update(i*2,left,right,val);
 48     else
 49     {
 50         update(i*2,left,mid,val);
 51         update(i*2+1,mid+1,right,val);
 52     }
 53     int tmp = max(tree[i*2].len1,tree[i*2+1].len1);
 54     tree[i].len1=max(tmp,tree[i*2].len3 + tree[i*2+1].len2);
 55     tree[i].len2=tree[i*2].len2;
 56     tree[i].len3=tree[i*2+1].len3;
 57     if(tree[i*2].len1 == tree[i*2].r-tree[i*2].l+1)//将子区间的len2和len3维护
 58         tree[i].len2+=tree[i*2+1].len2;
 59     if(tree[i*2+1].len1 == tree[i*2+1].r-tree[i*2+1].l+1)
 60         tree[i].len3+=tree[i*2].len3;
 61     return ;
 62 }
 63 int find(int i,int len)
 64 {
 65     if (tree[i].l==tree[i].r&&len==1) return tree[i].l;
 66     if (tree[i].mark!=-1)
 67     {
 68         int q=tree[i].mark,e,r;
 69         tree[i*2].mark=tree[i*2+1].mark=tree[i].mark;
 70         tree[i].mark=-1;
 71         if (q) e=0,r=0;
 72         else
 73         {
 74             e=tree[i*2].r-tree[i*2].l+1;
 75             r=tree[i*2+1].r-tree[i*2+1].l+1;
 76         }
 77         tree[i*2].len1=tree[i*2].len2=tree[i*2].len3=e;
 78         tree[i*2+1].len1=tree[i*2+1].len2=tree[i*2+1].len3=r;
 79     }
 80     if (tree[i*2].len1>=len) return find(i*2,len);
 81     else if (tree[i*2].len3+tree[i*2+1].len2>=len) return (tree[i*2].r-tree[i*2].len3+1);
 82     else if (tree[i*2+1].len1>=len) return find(i*2+1,len);
 83     else return 0;
 84 }
 85 int main()
 86 {
 87     int n,m,x,y,z,w;
 88     while (~scanf("%d %d",&n,&m))
 89     {
 90         build(1,1,n);
 91         while (m--)
 92         {
 93             scanf("%d",&x);
 94             if (x==1)
 95             {
 96                 scanf("%d",&y);
 97                 w=find(1,y);
 98                 printf("%d\n",w);
 99                 if (w) update(1,w,w+y-1,1);
100             }
101             if (x==2)
102             {
103                 scanf("%d %d",&y,&z);
104                 update(1,y,y+z-1,0);
105             }
106         }
107     }
108     return 0;
109 }

 

poj 3667(线段树 区间合并) 开房吧

标签:

原文地址:http://www.cnblogs.com/JJCHEHEDA/p/4729322.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!