hdu4614 二分+线段树

题意:给你1-n的花瓶   ,刚开始全是空的,现在有两种操作,

1:从花瓶a开始插入b朵花          如果不能插进去  输出字符串  否则输出最多插入的起点和终点;

2:把a-b的花瓶清空   输出处理花的个数;

结构体数组num【i】表示节点i空瓶的数目

线段树   开始deal函数对整个树初始化,update()更新函数 find()查询区间有多少个空瓶;     对于操作1    关键点是找到起点和终点   这里用二分  在【a,n】进行二分,

先二分起点       注意左右区间的变换(wa了好多次==)   然后在起点和n之间二分终点   最后更新  输出     对于操作2     直接查询即可;

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

#define LL(x) (x<<1)
#define RR(x) ((x<<1)|1)

struct node
{
    int cont;
}num[50000*4];
int deal(int L,int R,int point)
{
    num[point].cont=R-L+1;
    if(L==R) return 0;
    int mid=(L+R)/2;
    deal(L,mid,LL(point));
    deal(mid+1,R,RR(point));
    return 0;
}
int update(int L,int R,int left,int right,int point,int k)
{
    if(L==left&&R==right)
    {
        if(k==1) num[point].cont=R-L+1;
        else num[point].cont=0;
        return 0;
    }
    int mid=(L+R)/2;
    if(num[point].cont==R-L+1)
    {
        num[LL(point)].cont=mid-L+1;
        num[RR(point)].cont=R-mid;
    }
    if(num[point].cont==0)
    {
        num[LL(point)].cont=0;
        num[RR(point)].cont=0;
    }
    if(right<=mid)
    {
        update(L,mid,left,right,LL(point),k);
    }
    else if(left>mid)
    {
        update(mid+1,R,left,right,RR(point),k);
    }
    else
    {
        update(L,mid,left,mid,LL(point),k);
        update(mid+1,R,mid+1,right,RR(point),k);
    }
    num[point].cont=num[LL(point)].cont+num[RR(point)].cont;
    return 0;
}
int find(int L,int R,int left,int right,int point)
{
    if(L==left&&R==right)
    return num[point].cont;
    int sum=0;
    int mid=(L+R)/2;
    if(num[point].cont==R-L+1) return right-left+1;
    if(num[point].cont==0) return 0;
    if(right<=mid) sum+=find(L,mid,left,right,LL(point));
    else if(left>mid) sum+=find(mid+1,R,left,right,RR(point));
    else
    {
        sum+=find(L,mid,left,mid,LL(point));
        sum+=find(mid+1,R,mid+1,right,RR(point));
    }
    return sum;
}
int main()
{
    int n,m,k,i,j,T,a,b;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        deal(1,n,1);
        for(i=1;i<=m;i++)
        {
            scanf("%d%d%d",&k,&a,&b);
            if(k==1)
            {
                a+=1;
                int cont=find(1,n,a,n,1);
                if(cont==0) printf("Can not put any one.\n");
                else
                {
                    int left,right,mid;
                    int star,end;
                    left=a;
                    right=n;
                    while(left<=right)
                    {
                        mid=(left+right)/2;
                        if(find(1,n,left,mid,1)>0)
                        {
                            right=mid-1;
                            star=mid;
                        }
                        else left=mid+1; 

                    }
                    if(cont<=b)
                    {
                        left=a;
                        right=n;
                        while(left<=right)
                        {
                            mid=(left+right)/2;
                            if(find(1,n,mid,right,1)>0)
                            {
                                left=mid+1;
                                end=mid;
                            }
                            else right=mid-1;
                        }
                        //end=right;
                    }
                    else
                    {
                        left=a;
                        right=n;
                        while(left<=right)
                        {
                            mid=(left+right)/2;
                            if(find(1,n,star,mid,1)>=b)
                            {
                                right=mid-1;
                                end=mid;
                            }
                            else left=mid+1;
                        }
                        //end=left;
                    }
                    printf("%d %d\n",star-1,end-1);
                    update(1,n,star,end,1,-1);
                }
            }
            else
            {
                printf("%d\n",b-a+1-find(1,n,a+1,b+1,1));
                update(1,n,a+1,b+1,1,1);
            }

        }
        printf("\n");
    }
    return 0;
}
时间: 2024-10-01 13:29:46

hdu4614 二分+线段树的相关文章

【BZOJ-3110】K大数查询 整体二分 + 线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6265  Solved: 2060[Submit][Status][Discuss] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a

hdu4614(线段树+二分)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=4614 题意:给定一个区间[0,N-1],初始时每个位置上的数字都是0,可以对其进行以下两种操作: 1.在位置A开始寻找F(如果没有这么多,则有多少个就找多少个)个数值为0的位置,把位置上的数修改为1,并返回第一个和最后一个修改的位置 2.查询区间[a,b]内1的个数,并把区间[a,b]每个位置上的数修改为0 线段树功能:区间更替,区间求和. 分析:sum[rt]表示区间0的个数,二分找出0~L的nu

HDU5008 Boring String Problem(后缀数组 + 二分 + 线段树)

题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5008 Description In this problem, you are given a string s and q queries. For each query, you should answer that when all distinct substrings of string s were sorted lexicographically, which one is

(困难) CF 484E Sign on Fence,整体二分+线段树

Bizon the Champion has recently finished painting his wood fence. The fence consists of a sequence of n panels of 1 meter width and of arbitrary height. The i-th panel's height is hi meters. The adjacent planks follow without a gap between them. Afte

zoj 3888 Twelves Monkeys 二分+线段树维护次小值

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3888 Twelves Monkeys Time Limit: 5 Seconds      Memory Limit: 32768 KB James Cole is a convicted criminal living beneath a post-apocalyptic Philadelphia. Many years ago, the Earth's surf

bzoj1568: [JSOI2008]Blue Mary开公司 三分+二分+线段树

答案序列一定是个下凸壳,因此添加的等差数列与其之差是个单峰函数,可以先三分求出最值,再二分求出零点,然后用线段树,将得到的区间修改为一个等差数列. 这个做法应该比较好想吧,虽然比较慢…… #include<cstdio> #define Z int l=1,int r=N,int k=1 #define N 50000 #define M (l+r>>1) #define P (k<<1) #define S (k<<1|1) #define K l,r,k

计蒜客16492 building(二分线段树/分块)

题解: 考虑用线段树维护楼的最大值,然后这个问题就很简单了. 每次可以向左二分出比x高的第一个楼a,同理也可以向右二分出另一个楼b,如果a,b都存在,答案就是b-a-1. 注意到二分是可以直接在线段树上进行的,所以复杂度是O(nlogn). 当然这里是用分块做的,更暴力一些. #include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace st

51nod1287(二分/线段树区间最值&amp;单点更新)

题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1287 题意:中文题诶- 解法1:b[i] 存储 max(a[0], ....., a[i]),显然 b 是单调不减的,所以直接二分 x,再更新 a 和 b 数组即可: 代码: 1 #include <iostream> 2 #include <stdio.h> 3 using namespace std; 4 5 const int MAXN =

BZOJ 2527 Poi2011 Meteors 整体二分+线段树 / 可持久化线段树(MLE)

题目大意:给定一个环,每个节点有一个所属国家,k次事件,每次对[l,r]区间上的每个点点权加上一个值,求每个国家最早多少次操作之后所有点的点权和能达到一个值 首先我们考虑暴力想法 对于每个国家分开讨论 二分操作次数 但是这样每次Judge的时候我们要模拟1~mid所有的操作 浪费在这里的复杂度实在太大 这样做每个国家需要模拟O(klogk)次操作 时间复杂度O(nklogk) TLE 我们需要对浪费在这里的复杂度做一些改进 1.可持久化线段树(MLE) 每次二分一个mid之后 我们要找到mid次