hdu 4614 线段树 二分

题意:有n个花瓶,每个花瓶中只能放一朵花。

两种操作,一种是从A开始放F朵花,如果有的花瓶中已经有花则跳过这个花瓶,往下一个花瓶放;

    输出这次放的花的左右端点。如果能放但是放不完f朵输出n就好了

第二种是将区间[A,B]之间花瓶中的花清空。输出这次总共清理出了多少支花。

思路:第二种很明显可以用线段树实现,问题在第一种如何用线段树实现

  用二分  和 线段树 来判断右端点的位置  这样就可以了  第一次操作就成了区间更新

  并且查询左右端点

#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std;

#define ll long long
#define pb push_back
#define mp make_pair
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define fi first
#define se second
const int N = 5E4+3;
const int M  = 5e4+3;

int n,m;
int sum[N<<2],fst[N<<2],las[N<<2],L[N<<2],R[N<<2];
int col[N<<2];
//fst 开始空的  las最后空的  sum 空的数量
void pushup(int rt){
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
    if(las[rt<<1|1]!=-1)
        las[rt]=las[rt<<1|1];
    else las[rt]=las[rt<<1];
    if(fst[rt<<1]!=-1)
        fst[rt]=fst[rt<<1];
    else fst[rt] = fst[rt<<1|1];
    R[rt] = R[rt<<1|1];
    L[rt] = L[rt<<1];
}

void pushdown(int rt){
    //添加
    if(col[rt]==1){
        col[rt<<1]=col[rt<<1|1] = col[rt];
        sum[rt<<1]  = 0;
        sum[rt<<1|1] = 0;
        las[rt<<1]=las[rt<<1|1] = -1;
        fst[rt<<1]=fst[rt<<1|1] =-1;
        col[rt]=0;
    }
    else if(col[rt]==-1){
        col[rt<<1]=col[rt<<1|1] = col[rt];
        sum[rt<<1] = R[rt<<1]-L[rt<<1]+1;
        sum[rt<<1|1] = R[rt<<1|1]-L[rt<<1|1]+1;
        las[rt<<1] = R[rt<<1];
        fst[rt<<1] = L[rt<<1];
        las[rt<<1|1] = R[rt<<1|1];
        fst[rt<<1|1] = L[rt<<1|1];
        col[rt]=0;
    }
}

void build(int l,int r,int rt){
    col[rt] =0;
    if(l==r){
        L[rt] = r;
        R[rt] = l;
        sum[rt]=1;
        las[rt]=r;
        fst[rt]=l;
        return ;
    }
    int mid = (l+r)/2;
    build(lson);build(rson);
    pushup(rt);
}

void update(int l,int r,int rt, int a,int b,int val){

    if(a<=l && b>=r){

        if(val==1){
           if(sum[rt] ==0)return;
            col[rt] = val;
            sum[rt] = 0;
            las[rt]=fst[rt]=-1;
        }
        else if(val==-1){
            if(sum[rt]==R[rt]-L[rt]+1)return;
          // printf("%d %d %d %d %d %d\n",l,r,rt,a,b,sum[rt]);
            col[rt]=val;
            sum[rt]= R[rt]-L[rt]+1;
            las[rt]=R[rt];
            fst[rt]=L[rt];
           // printf("gai: %d %d %d %d %d %d\n",l,r,rt,a,b,sum[rt]);
        }
        return ;
    }

    pushdown(rt);

     int mid=(l+r)/2;
     if( a<=mid ) update(lson,a,b,val);
     if( b>mid ) update(rson ,a,b,val);
     pushup( rt );

}

int qfst(int l,int r,int rt,int a,int b){
    if(a<=l && b>=r){
        return fst[rt];
    }
    pushdown(rt);
    int mid =(l+r)/2;
    if(b<=mid)return qfst(lson,a,b);
    else if( a>mid )return qfst(rson,a,b);
    else {
        int ans1=-1;
        if(a<=mid)
            ans1 = qfst(lson,a,b);
        if(ans1!=-1)return ans1;
        if(b>mid)
        return qfst(rson,a,b);
    }
}

int qlst(int l,int r,int rt,int a,int b){
     if(a<=l && b>=r){
        return las[rt];
    }
     pushdown(rt);
    int mid =(l+r)/2;
    if(b<=mid)return qlst(lson,a,b);
    else if(a>mid)return qlst(rson,a,b);
    else {
        int ans1=-1;
        if(b>mid)
            ans1= qlst(rson,a,b);
        if(ans1!=-1)return ans1;
        if(a<=mid)return qlst(lson,a,b);
    }
}

int qnum(int l,int r,int rt,int a,int b){
    if(a<=l && b>=r){
        //printf("get :%d %d %d %d %d %d\n",l,r,rt,a,b,sum[rt]);
        int res = sum[rt];
        return res;
    }
    pushdown(rt);
    int ans = 0;
    int mid =(l+r)/2;
    if(a<=mid)
        ans+=qnum(lson,a,b);
    if(b>mid)
        ans+=qnum(rson,a,b);
    return ans;
}

int b_s(int st,int need){

    int l=st,r=n;
    int res = qnum(1,n,1,st,n);
    if(res==0)return -1;
    if(res<need)return n;
    int ans = n;
    while(l<=r){
        int m = (l+r)/2;
        if(qnum(1,n,1,st,m)>=need){
            ans = min(ans,m);
            r=m-1;
        }
        else l= m+1;
    }
    return ans;
}

int main(){

    int t;
    cin>>t;
    int op;
    while(t--){
        scanf("%d %d",&n,&m);

        build(1,n,1);

        while(m--){
            scanf("%d",&op);
            if(op==1){
                int x,f;scanf("%d %d",&x,&f);
                x++;
                int v = b_s(x,f);
                if(v==-1){
                    printf("Can not put any one.\n");
                }
                else {
                    printf("%d %d\n",qfst(1,n,1,x,v)-1 ,qlst(1,n,1,x,v)-1);
                    update(1,n,1,x,v,1);
                }
            }
            else if(op==2){
                int a,b;scanf("%d %d",&a,&b);
                a++;b++;
                int res = qnum(1,n,1,a,b);
                printf("%d\n",b-a+1-res);
                update(1,n,1,a,b,-1);
              //  cout<<sum[24]<<"!!"<<endl;
                res = qnum(1,n,1,a,b);
              // printf("update : %d\n",b-a+1-res);
            }
        }
        cout<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/wjhstudy/p/9852999.html

时间: 2024-10-07 19:52:32

hdu 4614 线段树 二分的相关文章

hdu 6070 线段树+二分

HDU - 6070 题意:提交了n次题目,每个题目都是最后一次提交的时候AC的,现在求一个区间,这个区间的AC率是最低的(只考虑这个区间内的题目,同样区间内最后交的一遍是AC的),求最低的AC率 思路:AC率=提交次数/题目数目,即区间长度/题目种类,siz[l,r]/(r-l+1)=p(siz[l,r]表示l r区间内的不同题目的个数,p表示AC率), 把式子做一下调整,siz[l,r]+p*l=p(r+1),二分p(0-1)用线段树维护siz[l,r]+l*p ,然后枚举r,每次更新,因为

HDU 3450 线段树+二分

点击打开链接 题意:给一个数字序列,问你长度大于2的且相邻两个数的差的绝对值不大于d的情况对9901取余 思路:看了根本不会,都没想到是线段树的题目,弱哭~~~,看了大牛们的题解,算是知道怎么回事了,对于当前的数A,那么以它为最后一个元素可以组成的情况是A-d到A+d的和,也可以这样想,A-d的已经组成了m种情况,那么在不影响小于d的情况下,可以直接将A放到A-d组成的左右序列中,那么直接加就可以了,而后更新A可以组成的情况,数据太大还需要离散化,然后二分找一下A-d和A+d的位置,数据可能没有

hdu 4339 线段树+二分

题意是给你两个字符串    进行两种操作   1: 修改其中一个字符串里的某个字符2:   询问从i起两个字符串最多由多少个是相同的: 先说一下做之前的想法   ,我是看别人介绍树状数组是看到这道题的    本也想用树状数组做  ,没想上去    然后就改为线段树了   ,有很明显的点更新,区间查询,所以选择线段树: 思路:  每个节点num[] 存3个值       p1  p2  flash   flash表示当前节点两个字符串是不是一样的   若是则为1否则为0    p1 p2为当前两个

HDU 4614 线段树+二分查找

Vases and Flowers 题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=4614 Problem Description Alice is so popular that she can receive many flowers everyday. She has N vases numbered from 0 to N-1. When she receive some flowers, she will try to put them

hdu 4893 (多校1007)Wow! Such Sequence!(线段树&amp;二分&amp;思维)

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 352    Accepted Submission(s): 104 Problem Description Recently, Doge got a funny birthday present from his new friend, Prot

hdu 5592 ZYB&#39;s Premutation (线段树+二分查找)

链接: http://acm.hdu.edu.cn/showproblem.php?pid=5592 Problem Description ZYB has a premutation P,but he only remeber the reverse log of each prefix of the premutation,now he ask you to  restore the premutation.Pair (i,j)(i<j) is considered as a reverse

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

HDU 4417 划分树+二分

题意:有n个数,m个询问(l,r,k),问在区间[l,r] 有多少个数小于等于k. 划分树--查找区间第k大的数.... 利用划分树的性质,二分查找在区间[l,r]小于等于k的个数. 如果在区间第 i 大的数tmp>k,则往下找,如果tmp<k,往上找. #include<cstdio> #include<stdlib.h> #include<string.h> #include<string> #include<map> #incl