hdu 4614 Vases and Flowers(线段树+二分)

Sample Input
  
  
2 10 5 1 3 5 2 4 5 1 1 8 2 3 6 1 8 8 10 6 1 2 5 2 3 4 1 0 8 2 2 5 1 4 4 1 2 3
 

Sample Output
  
  
3 7
2
1 9
4
Can not put any one.

2 6
2
0 9
4
4 5
2 3

题意  :   有n个花瓶,有两种操作 :  1 操作 是 以a花瓶为起点 插b 朵花 ,一个花瓶空的才能插  .如果一朵都不能插,输出 
Can not put any one.  ,能插输出插花的起始和尾的位置 .  2操作, 在 a.b花瓶间把花瓶清空,输入清空的花的数量.

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

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

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





#include <cstdio>

#include <cstring>
#include <cstdlib>
#include <algorithm>


#define lson l, m, rt << 1
#define rson m + 1, r, rt << 1 | 1


using namespace std;


const int MAXN = 50010;
const int INF = 1 << 30;


int N, Q, ok;
int flag[ MAXN << 2 ];    //无标记:-1,清空:0,占用:1
int sum[ MAXN << 2 ];     //区间占用区域总和
int len[ MAXN << 2 ];     //空闲区域长度总和
int addr[ MAXN << 2 ];    //本区间第一个空格的位置


void PushUp( int rt, int l, int r )
{
    int lc = rt << 1;
    int rc = rt << 1 | 1;
    sum[rt] = sum[lc] + sum[rc];
    len[rt] = len[lc] + len[rc];
    addr[rt] = min( addr[lc], addr[rc] );


    return;
}
void PushDown( int rt, int l, int r )
{
    int m = ( l + r ) >> 1;
    int lc = rt << 1;
    int rc = rt << 1 | 1;
    if ( flag[rt] != -1 )
    {
        flag[lc] = flag[rc] = flag[rt];
        if ( flag[rt] == 1 )   //如果占用
        {
            sum[lc] = m - l + 1;
            sum[rc] = r - m;
            len[lc] = len[rc] = 0;
            addr[lc] = addr[rc] = INF;   //本区间没有空格
        }
        else
        {
            sum[lc] = sum[rc] = 0;
            len[lc] = m - l + 1;
            len[rc] = r - m;
            addr[lc] = l;
            addr[rc] = m + 1;
        }
        flag[rt] = -1;
    }
    return;
}
void build( int l, int r, int rt )
{
    flag[rt] = -1;
    if ( l == r )
    {
        sum[rt] = 0;
        len[rt] = r - l + 1;
        addr[rt] = l;
        return;
    }
    int m = ( l + r ) >> 1;
    build( lson );
    build( rson );
    PushUp( rt, l, r );
    return;
}


int QuerySum( int L, int R, int l, int r, int rt )
{
    //printf( "preS: [%d, %d]: sum = %d\n", l, r, sum[rt] );
    if ( L <= l && r <= R ) return sum[rt];
    PushDown( rt, l, r );


    int m = ( l + r ) >> 1;
    int res = 0;


    if ( L <= m ) res += QuerySum( L, R, lson );
    if ( R > m )  res += QuerySum( L, R, rson );
    PushUp( rt, l, r );


    //printf( "afterS: [%d, %d]: sum = %d\n", l, r, sum[rt] );
    return res;
}


//查询大于等于st的第一个空格的位置
int QueryConti( int L, int R, int l, int r, int rt )
{
    if ( L <= l && r <= R )
    {
        return addr[rt];
    }
    PushDown( rt, l, r );
    int m = ( l + r ) >> 1;
    int tmp = INF;


    if ( L <= m ) tmp = min( tmp, QueryConti( L, R, lson ) );
    if ( R > m )  tmp = min( tmp, QueryConti( L, R, rson ) );


    PushUp( rt, l, r );


    return tmp;
}


void Update( int L, int R, int c, int l, int r, int rt )
{
    //printf( "pre UP [%d, %d]: sum = %d\n", l, r, sum[rt] );
    if ( L <= l && r <= R )
    {
        flag[rt] = c;
        if ( flag[rt] == 1 )   //如果占用
        {
            sum[rt] = r - l + 1;
            len[rt] = 0;
            addr[rt] = INF;   //本区间没有空格
        }
        else
        {
            sum[rt] = 0;
            len[rt] = r - l + 1;
            addr[rt] = l;
        }
        return;
    }
    PushDown( rt, l, r );


    int m = ( l + r ) >> 1;
    if ( L <= m ) Update( L, R, c, lson );
    if ( R > m )  Update( L, R, c, rson );
    PushUp( rt, l, r );


    //printf( "after UP [%d, %d]: sum = %d\n", l, r, sum[rt] );
    return;
}


int BiSearch( int l, int r, int st, int tar )
{
    //printf("tar=%d\n", tar);
    while ( l <= r )
    {
        int mid = ( l + r ) >> 1;
        int sum = QuerySum( st, mid, 0, N - 1, 1 );
        sum = mid - st + 1 - sum;
        if ( sum >= tar ) r = mid;
        else l = mid + 1;
        if ( l == r ) return l;
    }
    return l;
}


int main()
{
    //freopen( "s.out", "w", stdout );
    int T;
    scanf( "%d", &T );
    while( T-- )
    {
        scanf( "%d%d", &N, &Q );
        build( 0, N - 1, 1 );
        while ( Q-- )
        {
            int op, a, b;
            scanf( "%d%d%d", &op, &a, &b );
            if ( op == 1 )
            {
                if ( b == 0 ) continue;
                int ans = QuerySum( a, N - 1, 0, N - 1, 1 );
                if ( ans == N - a )
                    puts("Can not put any one.");
                else
                {
                    //printf( "%d %d\n", N - a, ans );
                    int FF = min( N - a - ans, b );
                    int left = QueryConti( a, N - 1, 0, N - 1, 1 );
                    int right = BiSearch( a, N - 1, a, FF );
                    printf( "%d %d\n", left, right );
                    Update( left, right, 1, 0, N - 1, 1 );
                }
            }
            else
            {
                int ans = QuerySum( a, b, 0, N - 1, 1 );
                printf( "%d\n", ans );
                Update( a, b, 0, 0, N - 1, 1 );
            }
            //puts("**********");
        }
        puts("");
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值