【POJ 3667 】 线段树之区间操作

题目连接:http://poj.org/problem?id=3667

 

题目大意:让你对一个区间进行操作。输入Q C 或者 Q C D。

Q ==1  输入 C: 表示让你求1-n中是否有连续的C个空hotel,如果有多个连续的C个空hotel,则取最左边的,并输出最左边的第一间hotel标号。让人住进去,那么这些空房就不能住人了。如果不存在连续的C个hotel,则输出 0。

Q==2   输入 C D: 表示 从标号C到C+D-1的hotel的房间全部要退房,那么这么hotel都变成空。

 

解题思路:

用到线段树的区间操作,具体解析见代码。

  1 #include <cstdio>

  2 #include <cmath>

  3 #include <iostream>

  4 #include <algorithm>

  5 using namespace std;

  6 

  7 #define lz 2*u,l,mid

  8 #define rz 2*u+1,mid+1,r

  9 const int maxn=50005;

 10 int  flag[4*maxn];   ///标记

 11 

 12 struct node

 13 {

 14     int lm; ///从左边第一个点开始最长的连续空hotel

 15     int rm; ///以右边最后一个结束的最长的连续空hotel

 16     int sm; ///整段区间最大的连续空hotel 

 17 } tree[4*maxn];

 18 

 19 void push_up(int u, int l, int r)   ///向上更新

 20 {

 21     tree[u].lm=tree[2*u].lm;          

 22     tree[u].rm=tree[2*u+1].rm;

 23     tree[u].sm=max(tree[2*u].sm,tree[2*u+1].sm);

 24     int mid=(l+r)>>1;

 25     if(tree[2*u].lm==mid-l+1) tree[u].lm+=tree[2*u+1].lm;  ///!!这里注意,当左孩子左边连续的达到整个区间时,要加上右孩子的左边区间

 26     if(tree[2*u+1].rm==r-mid) tree[u].rm+=tree[2*u].rm;   ///!!考虑右区间,同上

 27     int t=tree[2*u].rm+tree[2*u+1].lm;

 28     if(t>tree[u].sm) tree[u].sm=t;

 29 }

 30 

 31 void push_down(int u, int l, int r)  ///向下更新

 32 {

 33     if(flag[u]==-1) return ;

 34     if(flag[u])

 35     {

 36         flag[2*u]=flag[2*u+1]=flag[u];

 37         tree[2*u].lm=tree[2*u].rm=tree[2*u].sm=0;

 38         tree[2*u+1].lm=tree[2*u+1].rm=tree[2*u+1].sm=0;

 39         flag[u]=-1;

 40     }

 41     else

 42     {

 43         flag[2*u]=flag[2*u+1]=flag[u];

 44         int mid=(l+r)>>1;

 45         tree[2*u].lm=tree[2*u].rm=tree[2*u].sm=mid-l+1;

 46         tree[2*u+1].lm=tree[2*u+1].rm=tree[2*u+1].sm=r-mid;

 47         flag[u]=-1;

 48     }

 49 }

 50 

 51 void build(int u, int l, int r)  ///建树

 52 {

 53     flag[u]=-1;

 54     if(l==r)

 55     {

 56         tree[u].lm=tree[u].rm=tree[u].sm=1;

 57         return ;

 58     }

 59     int mid=(l+r)>>1;

 60     build(lz);

 61     build(rz);

 62     push_up(u,l,r);

 63 }

 64 

 65 void Update(int u, int l, int r, int tl, int tr, int c)   ///更新操作

 66 {

 67     if(tl<=l&&r<=tr)

 68     {

 69         tree[u].sm=tree[u].lm=tree[u].rm=(c==1?0:r-l+1);

 70         flag[u]= c;  

 71         return ;

 72     }

 73     push_down(u,l,r);   ///再次遇见此段区间时,延迟标记同步向下更新

 74     int mid=(l+r)>>1;

 75     if(tr<=mid) Update(lz,tl,tr,c);

 76     else if(tl>mid) Update(rz,tl,tr,c);

 77     else

 78     {

 79         Update(lz,tl,mid,c);    ///注意区间分隔开,tl,tr跨越两个左右区间

 80         Update(rz,mid+1,tr,c);

 81     }

 82     push_up(u,l,r);     ///递归的时候同步向上更新

 83 }

 84 

 85 int Query(int u, int l, int r, int num)   ///询问操作

 86 {

 87     if(l==r)

 88         return l;

 89     push_down(u,l,r);     ///延迟标记向下传递

 90     int mid=(l+r)>>1;

 91     if(tree[2*u].sm>=num) return Query(lz,num);

 92     else if(tree[2*u].rm+tree[2*u+1].lm>=num&&tree[2*u].rm>=1) return mid-tree[2*u].rm+1;   ///满足条件时,返回左边rm连续的hotel第一个房间标号

 93     else

 94         return Query(rz,num);

 95 }

 96 

 97 int main()

 98 {

 99     int n, m;

100     while(~scanf("%d%d",&n,&m))

101     {

102         build(1,1,n);

103         while(m--)

104         {

105             int p, u, v;

106             scanf("%d",&p);

107             if(p==1)

108             {

109                 scanf("%d",&u);

110                 if(tree[1].sm<u)  ///特判一下是否有这么多个连续的空hotel,没有则直接输出,不用操作

111                 {

112                     puts("0"); continue;

113                 }

114                 int p=Query(1,1,n,u);

115                 printf("%d\n",p);

116                 Update(1,1,n,p,p+u-1,1);

117             }

118             else

119             {

120                 scanf("%d%d",&u,&v);

121                 Update(1,1,n,u,u+v-1,0);

122             }

123         }

124     }

125     return 0;

126 }

 

 

你可能感兴趣的:(poj)