HDU 4614Vases and Flowers(不定区间->定区间)

题意:

插花和拔花的过程,1插,2拔,如果一个都不能插输出 “ ...” ,如果能插至少一朵花,但是不够插,就把其余的花扔掉


思路;

 lazy标记为1 时表示已空, -1时表示已满,sum表示空瓶子个数,first表示最左边空瓶位置,last表示最右边空瓶位置,-1表示无

自己第一次写的时候感觉的难点在于如何找到区间的右端点,发现kuangbin大神写了个二分,真是强,第一次做先断食用到二分。

具体二分操作是:

枚举右端点的第一个满足条件的位置,即统计l~r的sum(空瓶子个数),找到第一个满足条件的右侧瓶子位置。就可以将(l ~ ??) 转变为 (l ~ r)区间上的区间查询和修改的问题了。

区间特值查询:

之后是一个查(l~r)区间的存储值的问题,就简单多了,即查到(l~r)的第一个非空位置和最后一个非空位置,因为在二分的时候已经确定了r是最优的区间,但是不能直接输出t,各位可以自己体验下第二组数据,这是因为对于可以插,但是不够插的情况来说,二分只是返回了R (n)但是并非最后的第二个值的结果。

区间更新:

对于每次操作,1操作是一个插花的操作,对于l~r的区间都置为空。

2是一个拔花的操作,对于l~r的区间都只能1。

我这里标记的是 空表示不能插,  1表示能插。

sum记载的是区间空瓶子的个数。

总结一下:

昨晚搞了一晚上也没弄明白,因为自己一直都无法判断区间右端点的问题,下次线段树做的时候不管题中的要求是什么,对于区间操作,必须知道区间的始末位置,否则线段树是不能完成的。

#include <stdio.h>
#include <algorithm>
#include <iostream> 
using namespace std;
const int maxn=50005;
struct node
{
    int left,right;
    int lazy,first,last;
    int sum;
}tree[maxn*4];
int n,m;
void push_up(int i) 
{ 
    tree[i].sum=tree[i<<1].sum+tree[i<<1|1].sum;
    if(tree[i<<1].first!=-1)
        tree[i].first=tree[i<<1].first;
    else tree[i].first=tree[i<<1|1].first;
    if(tree[i<<1|1].last!=-1)
        tree[i].last=tree[i<<1|1].last;
    else
        tree[i].last=tree[i<<1].last;
}
void push_down(int i)
{ 
    if(tree[i].lazy==1)
    {
        tree[i<<1].first=tree[i<<1].left;
        tree[i<<1].last=tree[i<<1].right;
        tree[i<<1].sum=tree[i<<1].right-tree[i<<1].left+1;
        tree[i<<1].lazy=1;

        tree[i<<1|1].first=tree[i<<1|1].left;
        tree[i<<1|1].last=tree[i<<1|1].right;
        tree[i<<1|1].sum=tree[i<<1|1].right-tree[i<<1|1].left+1;
        tree[i<<1|1].lazy=1;
    }
    if(tree[i].lazy==-1)
    {
        tree[i<<1].first=-1;
        tree[i<<1].last=-1;
        tree[i<<1].sum=0;
        tree[i<<1].lazy=-1;

        tree[i<<1|1].first=-1;
        tree[i<<1|1].last=-1;
        tree[i<<1|1].sum=0;
        tree[i<<1|1].lazy=-1;
    }
    tree[i].lazy=0;
}
// lazy标记为1 时表示已空, -1时表示已满,sum表示空瓶子个数,first表示最左边空瓶位置,last表示最右边空瓶位置,-1表示无
void build(int i,int left,int right)
{
    tree[i].left=left,tree[i].right=right;
    tree[i].first=left,tree[i].last=right;
    tree[i].lazy=0,tree[i].sum=right-left+1;
    if(left==right)
        return ;
    int mid=(tree[i].left+tree[i].right)>>1;
    build(i<<1,left,mid);
    build(i<<1|1,mid+1,right);
}
void update(int i,int left,int right,int w)
{
    if(tree[i].left==left&&tree[i].right==right)
    {
        if(w==0)
        {
            tree[i].sum=0,tree[i].first=-1,tree[i].last=-1;
            tree[i].lazy=-1;
            return ;
        }
        else
        {
            tree[i].sum=right-left+1,tree[i].first=left,tree[i].last=right;
            tree[i].lazy=1;
            return ;
        }
    }
    push_down(i);
    int mid=(tree[i].left+tree[i].right)>>1;
    if(right<=mid)
        update(i<<1,left,right,w);
    else if(left>mid)
        update(i<<1|1,left,right,w);
    else
    {
        update(i<<1,left,mid,w);
        update(i<<1|1,mid+1,right,w);
    }
    push_up(i);
    return ;
}
int sum(int i,int left,int right)
{
    if(tree[i].left==left&&tree[i].right==right)
        return tree[i].sum;
    push_down(i);
    int mid=(tree[i].left+tree[i].right)>>1;
    if(right<=mid)
        return sum(i<<1,left,right);
    else if(left>mid)
        return sum(i<<1|1,left,right);
    else
        return sum(i<<1,left,mid)+sum(i<<1|1,mid+1,right);
}
int queryFirst_notEmpty(int i,int left,int right)
{
    if(tree[i].left==left&&tree[i].right==right)
    {
        return tree[i].first;
    }
    push_down(i);

    int mid=(tree[i].left+tree[i].right)>>1;
    int ans;
    if(right<=mid)
        ans=queryFirst_notEmpty(i<<1,left,right);
    else if(left>mid)
        ans=queryFirst_notEmpty(i<<1|1,left,right);
    else
    {
           ans=queryFirst_notEmpty(i<<1,left,mid);
        if(ans==-1)
            ans=queryFirst_notEmpty(i<<1|1,mid+1,right);
    }
    return ans;
}
int queryLast_notEmpty(int i,int left,int right)
{
    if(tree[i].left==left&&tree[i].right==right)
        return tree[i].last;
    push_down(i);
    int mid=(tree[i].left+tree[i].right)>>1;
    int ans;
    if(right<=mid)
        ans=queryLast_notEmpty(i<<1,left,right);
    else if(left>mid)
        ans=queryLast_notEmpty(i<<1|1,left,right);
    else
    {
        ans=queryLast_notEmpty(i<<1|1,mid+1,right);
        if(ans==-1)
            ans=queryLast_notEmpty(i<<1,left,mid);
    }
    return ans;
}
int bisearch(int A,int F)
{
    if(sum(1,A,n)==0)return -1;
    if(sum(1,A,n)<=F)return n;
    int l= A,r = n;
    int ans=A;
    while(l<=r)
    {
        int mid = (l+r)/2;
        if(sum(1,A,mid)>=F)
        {
            ans = mid;
            r = mid-1;
        }
        else l = mid+1;
    }
    return ans;
}
int main()
{   
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(1,1,n);
        int op,u,v;
        while(m--)
        {
            scanf("%d%d%d",&op,&u,&v);
            if(op == 1)
            {
                u++;
                int t = bisearch(u,v); 
                if(t==-1)
                {
                    printf("Can not put any one.\n");
                    continue;
                }
                printf("%d %d\n",queryFirst_notEmpty(1,u,t)-1,queryLast_notEmpty(1,u,t)-1);
                update(1,u,t,0);
            }
            else
            {
                u++,v++; 
                printf("%d\n",v-u+1-sum(1,u,v));
                update(1,u,v,1);
            }
        }
        printf("\n");
    }
    return 0;
}
/*
1
10 6
1 4 1
1 2 3
*/


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值