poj3667 hotel(线段树区间合并)
http://poj.org/problem?id=3667
之前网络赛水过一道区间合并的题 当时是全靠运气试对的 。
昨天纠结了一晚上也没看出来哪错,改的都跟人家代码一样了还是不对,今天又重新敲了一遍,莫名的就对了,,
开两个数组分别存这个区间两端点的连续区间 再开一标记数组 用来更新 向上向下都要更新
View Code
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define N 50010 7 int s[N<<2],kc[N<<2],lc[N<<2],rc[N<<2]; 8 void build(int l,int r,int w) 9 { 10 s[w] = lc[w] = rc[w] = r-l+1; 11 kc[w] = -1; 12 if(l==r) 13 return ; 14 int m = (l+r)/2; 15 build(l,m,w<<1); 16 build(m+1,r,w<<1|1); 17 } 18 void pushdown(int w,int c) 19 { 20 if(kc[w]!=-1) 21 { 22 kc[w<<1] = kc[w<<1|1] = kc[w]; 23 s[w<<1] = lc[w<<1] = rc[w<<1] = kc[w]?0:c-(c>>1); 24 s[w<<1|1] = lc[w<<1|1] = rc[w<<1|1] = kc[w]?0:c>>1; 25 kc[w] = -1; 26 } 27 } 28 void pushup(int w,int c) 29 { 30 lc[w] = lc[w<<1]; 31 rc[w] = rc[w<<1|1]; 32 if(lc[w]==c-(c>>1)) 33 lc[w]+=lc[w<<1|1]; 34 if(rc[w]==c>>1) 35 rc[w]+=rc[w<<1]; 36 s[w] = max(rc[w<<1]+lc[w<<1|1],max(s[w<<1],s[w<<1|1]));//找出区间中最长的连续段 37 } 38 void update(int a,int b,int c,int l,int r,int w) 39 { 40 if(l>=a&&b>=r) 41 { 42 s[w] = lc[w] = rc[w] = c?0:r-l+1; 43 kc[w] = c; 44 return ; 45 } 46 pushdown(w,r-l+1); 47 int m = (l+r)>>1; 48 if(a<=m) 49 update(a,b,c,l,m,w<<1); 50 if(b>m) 51 update(a,b,c,m+1,r,w<<1|1); 52 pushup(w,r-l+1); 53 } 54 int query(int c,int l,int r,int w) 55 { 56 if(l==r) 57 return l; 58 pushdown(w,r-l+1); 59 int m = (l+r)>>1; 60 if(s[w<<1]>=c) 61 return query(c,l,m,w<<1); 62 else 63 if(rc[w<<1]+lc[w<<1|1]>=c)//中间段 64 return m-rc[w<<1]+1; 65 return query(c,m+1,r,w<<1|1); 66 } 67 int main() 68 { 69 int i,j,k,n,m,x,d; 70 cin>>n>>m; 71 build(1,n,1); 72 while(m--) 73 { 74 cin>>k; 75 if(k==1) 76 { 77 cin>>x; 78 if(s[1]<x) 79 printf("0\n"); 80 else 81 { 82 int p = query(x,1,n,1); 83 cout<<p<<endl; 84 update(p,p+x-1,1,1,n,1);//将这一段更新为已被占 85 } 86 } 87 else 88 { 89 cin>>x>>d; 90 update(x,x+d-1,0,1,n,1);//将这一段更新为空 91 } 92 } 93 return 0; 94 }