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