hdu 4266 The Worm in the Apple (线段树)

/*
题意:给你N个花瓶,编号是0  到 N - 1 ,初始状态花瓶是空的,每个花瓶最多插一朵花。
然后有2个操作。
操作1,a b c ,往在a位置后面(包括a)插b朵花,输出插入的首位置和末位置。
操作2,a b ,输出区间[a , b ]范围内的花的数量,然后全部清空。


很显然这是一道线段树。区间更新,区间求和,这些基本的操作线段树都可以logN的时间范围内完成。
操作2,很显然就是线段树的区间求和,求出[a , b]范围内的花朵的数量,区间更新,将整个区间全部变成0。
操作1,这里我们首先需要找出他的首位置和末位置,所以需要二分他的位置。
首先我们二分他的首位置, l = a , r = n ,在这个区间内二分,找出第一个0的位置,那就是该操作的首位置pos1。
然后再二分他的末位置,l = pos1 , r = n ,找到第b个0,就是该操作的末位置pos2,然后区间更新[pos1 ,pos2]全部置为1。
*/
#include <cstdio>
# include <algorithm>
using namespace std;
#define lson l , m , rt << 1
#define rson m + 1 , r , rt << 1 | 1
///lson和rson分别表示结点的左儿子和右儿子
///rt表示当前子树的根(root),也就是当前所在的结点
const int maxn =60010;
///maxn是题目给的最大区间,而节点数要开4倍,确切的来说节点数要开大于maxn的最小2x的两倍
int sum[maxn<<2];///求和
int col[maxn<<2];///用来标记每个节点,为0则表示没有标记,否则为标记
int str[maxn];
void PushUP(int rt)///PushUP(int rt)是把当前结点的信息更新到父结点
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void PushDown(int  rt,int  m)///pushDown(int rt)是把当前结点的信息更新给儿子结点,m为分区间的长度
{
    if (col[rt])///被标记过,说明区间改变了
    {
        col[rt<<1] = col[rt<<1|1] = 1;
        sum[rt<<1] = (m - (m >> 1)) * col[rt];///更新左儿子的和
        sum[rt<<1|1] = (m >> 1) * col[rt];///更新右儿子的和
        col[rt] = -1;///将标记向儿子节点移动后,父节点的延迟标记去掉
        ///传递后,当前节点标记域清空
    }
    else
    {
        col[rt<<1] = col[rt<<1|1] = 0;
        sum[rt<<1] = sum[rt<<1|1] = 0;
        col[rt] = -1;
    }
}
void build(int l,int  r,int rt)///建树
{
    col[rt] = -1;
    if (l == r)
    {
        sum[rt]=0;
        //  scanf("%lld",&sum[rt]);
        return ;
    }
    int m = (l + r) >> 1;
    build(lson);
    build(rson);
    PushUP(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        col[rt]= c;
        sum[rt]= c *(r - l +1);
        return;
    }
    if(col[rt]!=-1)
        PushDown(rt , r - l +1);
    int m =(l + r)>>1;
    if(L <= m) update(L , R , c , lson);
    if(R > m) update(L , R , c , rson);
    PushUP(rt);
}
int query(int L,int R,int l,int r,int rt)///区间求和
{
    if (L <= l && r <= R)
    {
        return sum[rt];
    }
    if(col[rt]!=-1)
        PushDown(rt , r - l + 1);///要取rt子节点的值时,也要先把rt的延迟标记向下移动
    int m = (l + r) >> 1;
    int  ret = 0;
    if (L <= m) ret += query(L , R , lson);
    if (m < R) ret += query(L , R , rson);
    return ret;
}
int main()
{
    int t,m,n,a,b,c;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        build(1,n,1);
        while(m--)
        {
            scanf("%d",&a);
            if(a==1)
            {
                scanf("%d%d",&b,&c);
                b++;
                c=min(c,(n-b+1)-query(b,n,1,n,1));
                if(c==0)
                {
                    printf("Can not put any one.\n");
                    continue;
                }
                int left=b;
                int right=n;
                while(left<=right)
                {
                    int mid=(left+right)/2;
                    if(query(b,mid,1,n,1)<mid-b+1)
                        right=mid-1;
                    else
                        left=mid+1;
                }
                b=left;
                right=n;
                while(left<=right)
                {
                    int mid=(left+right)/2;
                    int ans1=query(b,mid,1,n,1);
                    int ans2=mid-b+1;
                    int ans=ans2-ans1;
                    if(ans<c)
                        left=mid+1;
                    else
                        right=mid-1;
                }
                if(left>n)
                    left=n;
                printf("%d %d\n",b-1,left-1);
                update(b,left,1,1,n,1);
            }
            else
            {
                scanf("%d%d",&b,&c);
                b++;
                c++;
                if(b>=n)
                    b=n;
                if(c>=n)
                    c=n;
                int ans=query(b,c,1,n,1);
                printf("%d\n",ans);
                update(b,c,0,1,n,1);
                // printf("%d\n",query(b,c,1,n,1));

            }
        }
        printf("\n");
    }
    return 0;
}
/*
10
10 4
1 2 9
1 0 9
2 0 9
2 0 1
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
*/

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值