HDU 4614 Vases and Flowers 线段树 + 二分

线段树节点记录内容请见代码注释

操作1:每次查询区间 [A, N - 1] 中第一个空格的位置,然后在[ A, N - 1 ]中二分右端点的位置。实际放的花的数量是 要求数量 与 剩余空格数量 之间的最小值

如果[ A, N - 1 ]中已经没有空格了,就不能放了。

操作2:求和与成端更新,线段树基本操作不解释

比赛的时候把PushDown函数写错了,样例死活不过,比赛结束之后才看出来,2A之,orz……要不要这么伤人……

 

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <algorithm>
  5 
  6 #define lson l, m, rt << 1
  7 #define rson m + 1, r, rt << 1 | 1
  8 
  9 using namespace std;
 10 
 11 const int MAXN = 50010;
 12 const int INF = 1 << 30;
 13 
 14 int N, Q, ok;
 15 int flag[ MAXN << 2 ];    //无标记:-1,清空:0,占用:1
 16 int sum[ MAXN << 2 ];     //区间占用区域总和
 17 int len[ MAXN << 2 ];     //空闲区域长度总和
 18 int addr[ MAXN << 2 ];    //本区间第一个空格的位置
 19 
 20 void PushUp( int rt, int l, int r )
 21 {
 22     int lc = rt << 1;
 23     int rc = rt << 1 | 1;
 24     sum[rt] = sum[lc] + sum[rc];
 25     len[rt] = len[lc] + len[rc];
 26     addr[rt] = min( addr[lc], addr[rc] );
 27 
 28     return;
 29 }
 30 void PushDown( int rt, int l, int r )
 31 {
 32     int m = ( l + r ) >> 1;
 33     int lc = rt << 1;
 34     int rc = rt << 1 | 1;
 35     if ( flag[rt] != -1 )
 36     {
 37         flag[lc] = flag[rc] = flag[rt];
 38         if ( flag[rt] == 1 )   //如果占用
 39         {
 40             sum[lc] = m - l + 1;
 41             sum[rc] = r - m;
 42             len[lc] = len[rc] = 0;
 43             addr[lc] = addr[rc] = INF;   //本区间没有空格
 44         }
 45         else
 46         {
 47             sum[lc] = sum[rc] = 0;
 48             len[lc] = m - l + 1;
 49             len[rc] = r - m;
 50             addr[lc] = l;
 51             addr[rc] = m + 1;
 52         }
 53         flag[rt] = -1;
 54     }
 55     return;
 56 }
 57 void build( int l, int r, int rt )
 58 {
 59     flag[rt] = -1;
 60     if ( l == r )
 61     {
 62         sum[rt] = 0;
 63         len[rt] = r - l + 1;
 64         addr[rt] = l;
 65         return;
 66     }
 67     int m = ( l + r ) >> 1;
 68     build( lson );
 69     build( rson );
 70     PushUp( rt, l, r );
 71     return;
 72 }
 73 
 74 int QuerySum( int L, int R, int l, int r, int rt )
 75 {
 76     //printf( "preS: [%d, %d]: sum = %d\n", l, r, sum[rt] );
 77     if ( L <= l && r <= R ) return sum[rt];
 78     PushDown( rt, l, r );
 79 
 80     int m = ( l + r ) >> 1;
 81     int res = 0;
 82 
 83     if ( L <= m ) res += QuerySum( L, R, lson );
 84     if ( R > m )  res += QuerySum( L, R, rson );
 85     PushUp( rt, l, r );
 86 
 87     //printf( "afterS: [%d, %d]: sum = %d\n", l, r, sum[rt] );
 88     return res;
 89 }
 90 
 91 //查询大于等于st的第一个空格的位置
 92 int QueryConti( int L, int R, int l, int r, int rt )
 93 {
 94     if ( L <= l && r <= R )
 95     {
 96         return addr[rt];
 97     }
 98     PushDown( rt, l, r );
 99     int m = ( l + r ) >> 1;
100     int tmp = INF;
101 
102     if ( L <= m ) tmp = min( tmp, QueryConti( L, R, lson ) );
103     if ( R > m )  tmp = min( tmp, QueryConti( L, R, rson ) );
104 
105     PushUp( rt, l, r );
106 
107     return tmp;
108 }
109 
110 void Update( int L, int R, int c, int l, int r, int rt )
111 {
112     //printf( "pre UP [%d, %d]: sum = %d\n", l, r, sum[rt] );
113     if ( L <= l && r <= R )
114     {
115         flag[rt] = c;
116         if ( flag[rt] == 1 )   //如果占用
117         {
118             sum[rt] = r - l + 1;
119             len[rt] = 0;
120             addr[rt] = INF;   //本区间没有空格
121         }
122         else
123         {
124             sum[rt] = 0;
125             len[rt] = r - l + 1;
126             addr[rt] = l;
127         }
128         return;
129     }
130     PushDown( rt, l, r );
131 
132     int m = ( l + r ) >> 1;
133     if ( L <= m ) Update( L, R, c, lson );
134     if ( R > m )  Update( L, R, c, rson );
135     PushUp( rt, l, r );
136 
137     //printf( "after UP [%d, %d]: sum = %d\n", l, r, sum[rt] );
138     return;
139 }
140 
141 int BiSearch( int l, int r, int st, int tar )
142 {
143     //printf("tar=%d\n", tar);
144     while ( l <= r )
145     {
146         int mid = ( l + r ) >> 1;
147         int sum = QuerySum( st, mid, 0, N - 1, 1 );
148         sum = mid - st + 1 - sum;
149         if ( sum >= tar ) r = mid;
150         else l = mid + 1;
151         if ( l == r ) return l;
152     }
153     return l;
154 }
155 
156 int main()
157 {
158     //freopen( "s.out", "w", stdout );
159     int T;
160     scanf( "%d", &T );
161     while( T-- )
162     {
163         scanf( "%d%d", &N, &Q );
164         build( 0, N - 1, 1 );
165         while ( Q-- )
166         {
167             int op, a, b;
168             scanf( "%d%d%d", &op, &a, &b );
169             if ( op == 1 )
170             {
171                 if ( b == 0 ) continue;
172                 int ans = QuerySum( a, N - 1, 0, N - 1, 1 );
173                 if ( ans == N - a )
174                     puts("Can not put any one.");
175                 else
176                 {
177                     //printf( "%d %d\n", N - a, ans );
178                     int FF = min( N - a - ans, b );
179                     int left = QueryConti( a, N - 1, 0, N - 1, 1 );
180                     int right = BiSearch( a, N - 1, a, FF );
181                     printf( "%d %d\n", left, right );
182                     Update( left, right, 1, 0, N - 1, 1 );
183                 }
184             }
185             else
186             {
187                 int ans = QuerySum( a, b, 0, N - 1, 1 );
188                 printf( "%d\n", ans );
189                 Update( a, b, 0, 0, N - 1, 1 );
190             }
191             //puts("**********");
192         }
193         puts("");
194     }
195     return 0;
196 }

 

转载于:https://www.cnblogs.com/GBRgbr/p/3214782.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值