线段树 区间合并

poj3667 Hotel

区间合并入门题,照着代码打的,

题意:1 a:询问是不是有连续长度为a的空房间,有的话住进最左边
       2 a b:将[a,a+b-1]的房间清空
思路:记录区间中最长的空房间,开三个数组,msum[rt]表示节点rt内连续的1的个数的最大值,lsum[rt]表示从节点rt左端点开始连续1的个数,rsum[rt]表示从节点rt右端点开始连续1的个数。。
线段树操作:update:区间替换 query:询问满足条件的最左端点

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<string>
 6 #include<cmath>
 7 #include<map>
 8 #include<queue>
 9 
10 using namespace std;
11 
12 #define mnx 50005
13 #define Pi acos(-1.0)
14 #define ull unsigned long long
15 #define ll long long 
16 #define inf 0x3f3f3f3f
17 #define eps 1e-8
18 #define MP make_pair
19 #define lson l, m, rt << 1
20 #define rson m+1, r, rt << 1 | 1
21 #define mod 2333333
22 
23 int msum[mnx<<2], lsum[mnx<<2], rsum[mnx<<2], cover[mnx<<2];
24 void pushup( int rt, int m ){
25     lsum[rt] = lsum[rt<<1];
26     rsum[rt] = rsum[rt<<1|1];
27     if( lsum[rt] == m - ( m >> 1 ) ) lsum[rt] += lsum[rt<<1|1];
28     if( rsum[rt] == ( m >> 1 ) ) rsum[rt] += rsum[rt<<1];
29     msum[rt] = max( lsum[rt<<1|1] + rsum[rt<<1], max( msum[rt<<1], msum[rt<<1|1] ) );
30 }
31 void pushdown( int rt, int m ){
32     if( cover[rt] != -1 ){
33         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
34         msum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : m - ( m >> 1 );
35         msum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : m >> 1;
36         cover[rt] = -1;
37     }
38 }
39 void build( int l, int r, int rt ){
40     msum[rt] = lsum[rt] = rsum[rt] = r - l + 1;
41     if( l == r ) return;
42     int m = ( l + r ) >> 1;
43     build( lson ); build( rson );
44 }
45 void update( int L, int R, int v, int l, int r, int rt ){
46     if( L <= l && R >= r ){
47         msum[rt] = rsum[rt] = lsum[rt] = v ? 0 : r - l + 1;
48         cover[rt] = v;
49         return ;
50     }
51     pushdown( rt, r - l + 1 );
52     int m = ( l + r ) >> 1;
53     if( L <= m ) update( L, R, v, lson );
54     if( R > m ) update( L, R, v, rson );
55     pushup( rt, r - l + 1 );
56 }
57 int query( int v, int l, int r, int rt ){
58     if( l == r ) return l;
59     pushdown( rt, r - l + 1 );
60     int m = ( l + r ) >> 1;
61     if( msum[rt<<1] >= v ) return query( v, lson );
62     else if( rsum[rt<<1] + lsum[rt<<1|1] >= v ) return m - rsum[rt<<1] + 1;
63     else return query( v, rson );
64 }
65 int main(){
66     int n, m;
67     while( scanf( "%d %d", &n, &m ) != EOF ){
68         memset( cover, -1, sizeof(cover) );
69         build( 1, n, 1 );
70         int op, a, b;
71         while( m-- ){
72             scanf( "%d", &op );
73             if( op == 1 ){
74                 scanf( "%d", &a );
75                 if( msum[1] < a ){
76                     puts( "0" ); continue;
77                 }
78                 int ans = query( a, 1, n, 1 );
79                 printf( "%d
", ans );
80                 update( ans, ans + a - 1, 1, 1, n, 1 );
81             }
82             else{
83                 scanf( "%d %d", &a, &b );
84                 update( a, a + b - 1, 0, 1, n, 1 );
85             }
86         }
87     }
88     return 0;
89 }
View Code

 hdu 1540 Tunnel Warfare

在yamiedie的指导下,过题总是那么轻松。。题目意思很简单,有n个村庄,一开始左右相连,D x表示这个村庄被破坏,就不能与左右两个村庄相连,R 表示修复最近一个被破坏的村庄,Q x表示询问和x村庄相连续的村庄有多少个。。

做法:线段树的区间连续问题。。D x 就是单点更新,跟上一题差不多。。Q x就先查询x有没有被破坏,没有被破坏就查询区间[1, x-1]的右端点的连续个数rsum[],再查询[x+1,n]的左端点的连续个数lsum[],注意 x - 1 > 0 和 x + 1 <= n的条件,不然会跪的。。

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<string>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<vector>
  9 
 10 using namespace std;
 11 
 12 #define mnx 200050
 13 #define mxn 50050
 14 #define LL long long
 15 #define mod 1000000007
 16 #define inf 0x3f3f3f3f
 17 #define eps 1e-10
 18 #define Pi acos(-1.0)
 19 #define lson l, m, rt << 1
 20 #define rson m + 1, r, rt << 1 | 1
 21 
 22 int lsum[mnx], rsum[mnx], msum[mnx], pre[mxn], n;
 23 bool vis[mxn];
 24 void build( int l, int r, int rt ){
 25     lsum[rt] = rsum[rt] = msum[rt] = r - l + 1;
 26     if( l == r ){
 27         return ;
 28     }
 29     int m = ( l + r ) >> 1;
 30     build( lson );
 31     build( rson );
 32 }
 33 void pushup( int rt, int m ){
 34     lsum[rt] = lsum[rt<<1];
 35     rsum[rt] = rsum[rt<<1|1];
 36     if( lsum[rt<<1] == m - ( m >> 1 ) ) lsum[rt] += lsum[rt<<1|1];
 37     if( rsum[rt<<1|1] == ( m >> 1 ) ) rsum[rt] += rsum[rt<<1];
 38     msum[rt] = max( lsum[rt<<1|1] + rsum[rt<<1], max( msum[rt<<1], msum[rt<<1|1] ) );
 39 }
 40 void update( int ok, int k, int l, int r, int rt ){
 41     if( l == r ){
 42         msum[rt] = lsum[rt] = rsum[rt] = ok ? r - l + 1 : 0;
 43         return ;
 44     }
 45     int m = ( l + r ) >> 1;
 46     if( k <= m ) update( ok, k, lson );
 47     else update( ok, k, rson );
 48     pushup( rt, r - l + 1 );
 49 }
 50 int query1( int L, int R, int l, int r, int rt ){
 51     if( L == l && R == r ){
 52         return rsum[rt];
 53     }
 54     int m = ( l + r ) >> 1;
 55     if( R <= m ) return query1( L, R, lson );
 56     if( L > m ) return query1( L, R, rson );
 57     int ret = query1( m + 1, R, rson );
 58     if( ret == R - m ){
 59         ret += query1( L, m, lson ); 
 60     }
 61     return ret;
 62 }
 63 int query2( int L, int R, int l, int r, int rt ){
 64     if( L == l && R == r ){
 65         return lsum[rt];
 66     }
 67     int m = ( l + r ) >> 1;
 68     if( R <= m ) return query2( L, R, lson );
 69     if( L > m ) return query2( L, R, rson );
 70     int ret = query2( L, m, lson );
 71     if( ret == m - L + 1 ){
 72         ret += query2( m + 1, R, rson ); 
 73     }
 74     return ret;
 75 }
 76 int main(){
 77     int m;
 78     while( scanf( "%d %d", &n, &m ) != EOF ){
 79         build( 1, n, 1 );
 80         memset( vis, 0, sizeof(vis) );
 81         char ch[2]; int k, cnt = 0;
 82         while( m-- ){
 83             scanf( "%s", ch );
 84             if( ch[0] == 'R' ){
 85                 if( cnt == 0 ) continue;
 86                 k = pre[cnt--];
 87                 if( vis[k] ) update( 1, k, 1, n, 1 );
 88                 vis[k] = 0;
 89             }
 90             else if( ch[0] == 'D' ){
 91                 scanf( "%d", &k );
 92                 if( k < 1 || k > n ) continue;
 93                 pre[++cnt] = k;
 94                 if( !vis[k] ) update( 0, k, 1, n, 1 );
 95                 vis[k] = 1;
 96             }
 97             else{
 98                 scanf( "%d", &k );
 99                 int ans = query1( k, k, 1, n, 1 );
100                 if( ans ){
101                     if( k > 1 ) ans += query1( 1, k-1, 1, n, 1 );
102                     if( k < n ) ans += query2( k+1, n, 1, n, 1 );
103                 } 
104                 printf( "%d
", ans );
105             }
106         }
107     }
108     return 0;
109 }
View Code

 hdu 2871 Memory Control

题意:有四个指令,New x就是申请一段长度为x的内存空间;Free  x就是找一个包含X的区间,把那个区间释放掉;Get x就是从1到N 第x个区间;Reset 就是把所有的内存释放掉。

做法:线段树,int lsum[mnx], rsum[mnx], msum[mnx], sum[mnx], tot[mnx], L[mnx], R[mnx], cover[mnx], cnt。。先解释一下各个数组的含义,msum[rt]表示节点rt内连续的可用空间的长度的最大值,lsum[rt]表示从节点rt左端点开始连续可用空间的长度,rsum[rt]表示从节点rt右端点开始连续可用空间的长度;cover[rt] 表示这个区间有没有被用,-1就是最初没有使用的状态,1表示这个区间全都用了,0表示这个区间已经释放掉了;sum[rt]用来记录这是第cnt个被用的区间,sum[rt]=0表示这个区间没有被用,L[cnt]和R[cnt]表示第cnt个被用的区间的左端点和右端点是多少,这3个数组用来辅助Free操作;tot[]就是用来辅助Get操作,表示当前有多少个区间被用了,每用一个区间,就在该区间的左端点的tot[]上加上1,每释放一个区间,就在释放的区间的左端点减去1。。

对于Reset操作,不能重建线段树,这样会超时,只需要从 (1, n)成段更新,利用懒惰标记向下更新。。update函数就是用来更新 要用的区间或者要释放的区间,update1就是用来更新 左端点 tot[]的值,query函数就是在New x的时候,查找可用内存的左端点,find函数就是在Free x的时候查找 x的cnt值, findtot就是在Get x的时候查找 第x个被用的区间的左端点

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 #include<string>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 #include<vector>
  9 
 10 using namespace std;
 11 
 12 #define mnx 200050
 13 #define mxn 50050
 14 #define LL long long
 15 #define mod 1000000007
 16 #define inf 0x3f3f3f3f
 17 #define eps 1e-10
 18 #define Pi acos(-1.0)
 19 #define lson l, m, rt << 1
 20 #define rson m + 1, r, rt << 1 | 1
 21 
 22 int lsum[mnx], rsum[mnx], msum[mnx], sum[mnx], tot[mnx], L[mnx], R[mnx], cover[mnx], cnt;
 23 void build( int l, int r, int rt ){
 24     lsum[rt] = rsum[rt] = msum[rt] = r - l + 1;
 25     cover[rt] = -1, sum[rt] = 0, tot[rt] = 0;
 26     if( l == r ) return;
 27     int m = ( l + r ) >> 1;
 28     build( lson );
 29     build( rson );
 30 }
 31 void pushup( int rt, int m ){
 32     tot[rt] = tot[rt<<1] + tot[rt<<1|1];
 33     lsum[rt] = lsum[rt<<1];
 34     rsum[rt] = rsum[rt<<1|1];
 35     if( lsum[rt<<1] == ( m - ( m >> 1 ) ) ) lsum[rt] += lsum[rt<<1|1];
 36     if( rsum[rt<<1|1] == ( m >> 1 ) ) rsum[rt] += rsum[rt<<1];
 37     msum[rt] = max( rsum[rt<<1] + lsum[rt<<1|1], max( msum[rt<<1], msum[rt<<1|1] ) );
 38 }
 39 void pushdown( int rt, int m ){
 40     if( cover[rt] != -1 ){
 41         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
 42         msum[rt<<1] = lsum[rt<<1] = rsum[rt<<1] = cover[rt] ? 0 : m - ( m >> 1 );
 43         msum[rt<<1|1] = lsum[rt<<1|1] = rsum[rt<<1|1] = cover[rt] ? 0 : ( m >> 1 );
 44         if( cover[rt] ){
 45             sum[rt<<1] = sum[rt<<1|1] = sum[rt];
 46         }
 47         else sum[rt<<1] = sum[rt<<1|1] = 0;
 48         if( tot[rt] == 0 ) tot[rt<<1] = tot[rt<<1|1] = tot[rt];
 49         cover[rt] = -1;
 50     }
 51 }
 52 void update( int L, int R, int v, int l, int r, int rt ){
 53     if( L <= l && R >= r ){
 54         lsum[rt] = rsum[rt] = msum[rt] = v ? 0 : r - l + 1;
 55         sum[rt] = v ? cnt : 0; cover[rt] = v;
 56         return;
 57     }
 58     pushdown( rt, r - l + 1 );
 59     int m = ( l + r ) >> 1;
 60     if( L <= m ) update( L, R, v, lson );
 61     if( R > m ) update( L, R, v, rson );
 62     pushup( rt, r -l + 1 );
 63 }
 64 void update1( int k, int v, int l, int r, int rt ){
 65     if( l == r ){
 66         tot[rt] = v;
 67         return ;
 68     }
 69     pushdown( rt, r - l + 1 );
 70     int m = ( l + r ) >> 1;
 71     if( k <= m ) update1( k, v, lson );
 72     else update1( k, v, rson );
 73     pushup( rt, r - l + 1 );
 74 }
 75 int query( int k, int l, int r, int rt ){
 76     if( l == r ) return l;
 77     pushdown( rt, r - l + 1 );
 78     int m = ( l + r ) >> 1, ret;
 79     if( msum[rt<<1] >= k ) ret = query( k, lson );
 80     else if( rsum[rt<<1] + lsum[rt<<1|1] >= k ){
 81         ret = m - rsum[rt<<1] + 1;
 82     }
 83     else ret = query( k, rson );
 84     pushup( rt, r -l + 1 );
 85     return ret;
 86 }
 87 int find( int k, int l, int r, int rt ){
 88     if( l == r ){
 89         return sum[rt];
 90     }
 91     pushdown( rt, r - l + 1 );
 92     int m = ( l + r ) >> 1, ret;
 93     if( k <= m ) ret = find( k, lson );
 94     else ret = find( k, rson );
 95     pushup( rt, r - l + 1 );
 96     return ret;
 97 }
 98 int findtot( int k, int l, int r, int rt ){
 99     if( l == r ){
100         return l;
101     }
102     pushdown( rt, r - l + 1 );
103     int m = ( l + r ) >> 1, ret;
104     if( tot[rt<<1] >= k ) ret = findtot( k, lson );
105     else ret = findtot( k - tot[rt<<1], rson );
106     pushup( rt, r -l + 1 );
107     return ret;
108 }
109 int main(){
110     int n, m, flag = 0;
111     //freopen( "in.txt", "w", stdout );
112     while( scanf( "%d %d", &n, &m ) != EOF ){
113         cnt = 0;
114         build( 1, n, 1 );
115         char ch[50]; int k;
116         while( m-- ){
117             scanf( "%s", ch );
118             if( ch[0] == 'R' ){
119                 puts( "Reset Now" );
120                 update( 1, n, 0, 1, n, 1 );
121                 tot[1] = 0;
122                 cnt = 0;
123             }
124             else if( ch[0] == 'N' ){
125                 scanf( "%d", &k );
126                 if( msum[1] < k || k <= 0 || k > n ){
127                     puts( "Reject New" );continue;
128                 }
129                 ++cnt;
130                 int ans = query( k, 1, n, 1 );
131                 L[cnt] = ans, R[cnt] = ans + k - 1;
132                 printf( "New at %d
", ans );
133                 update( ans, ans + k - 1, 1, 1, n, 1 );
134                 update1( ans, 1, 1, n, 1 );
135             }
136             else if( ch[0] == 'F' ){
137                 scanf( "%d", &k );
138                 int ans = find( k, 1, n, 1 );
139                 if( ans <= 0 || k <= 0 || k > n ){
140                     puts( "Reject Free" ); continue;
141                 }
142                 printf( "Free from %d to %d
", L[ans], R[ans] );
143                 update( L[ans], R[ans], 0, 1, n, 1 );
144                 update1( L[ans], 0, 1, n, 1 );
145             }
146             else{
147                 scanf( "%d", &k );
148                 if( tot[1] < k || k <= 0 ){
149                     puts( "Reject Get" ); continue;
150                 }
151                 int ans = findtot( k, 1, n, 1 );
152                 printf( "Get at %d
", ans );
153             }
154         }
155         cout<<endl;
156     }
157     return 0;
158 }
View Code
原文地址:https://www.cnblogs.com/LJ-blog/p/3917104.html