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 in the vases, one flower in one vase. She randomly choose the vase A and try to put a flower in the vase. If the there is no flower in the vase, she will put a flower in it, otherwise she skip this vase. And then she will try put in the vase A+1, A+2, ..., N-1, until there is no flower left or she has tried the vase N-1. The left flowers will be discarded. Of course, sometimes she will clean the vases. Because there are too many vases, she randomly choose to clean the vases numbered from A to B(A <= B). The flowers in the cleaned vases will be discarded.

Input

  The first line contains an integer T, indicating the number of test cases.
  For each test case, the first line contains two integers N(1 < N < 50001) and M(1 < M < 50001). N is the number of vases, and M is the operations of Alice. Each of the next M lines contains three integers. The first integer of one line is K(1 or 2). If K is 1, then two integers A and F follow. It means Alice receive F flowers and try to put a flower in the vase A first. If K is 2, then two integers A and B follow. It means the owner would like to clean the vases numbered from A to B(A <= B).

Output

  For each operation of which K is 1, output the position of the vase in which Alice put the first flower and last one, separated by a blank. If she can not put any one, then output ‘Can not put any one.‘. For each operation of which K is 2, output the number of discarded flowers.
  Output one blank line after each test case.

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

题意

有一个初始全为零的序列,支持两种操作:

1.1 x y 从x开始往后找y个为0的位置并赋值为1,找不满没关系。输出未赋值时第一个为零位置和最后一个为零的位置,如果没有一个为零的位置输出 Can not put any one.

2.2 x y 输出x到y的和,并将x到y赋值成0

题解

主要操作就是区间覆盖和区间求和,至于操作一,我们可以二分查找,左区间就是x,有区间r二分,sum[x,r]随r单调不减,我们只要求最左边的sum[x,r]=1和sum[x,r]=y的位置即可,还有些细节可以仔细想想。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF 0x7f7f7f7f
#define N 100050
int n,m;
template<typename T>void read(T&x)
{
    ll k=0; char c=getchar();
    x=0;
    while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
    if (c==EOF)exit(0);
    while(isdigit(c))x=x*10+c-'0',c=getchar();
    x=k?-x:x;
}
void read_char(char &c)
{while(!isalpha(c=getchar())&&c!=EOF);}
struct Node{int l,r,lazy,sum;};
struct segmentTree
{
    Node tr[N<<2];
    void push_up(int x);
    void push_down(int x);
    void bt(int x,int l,int r);
    void update(int x,int l,int r,int tt);
    int query(int x,int l,int r);
    int ef(int k,int x,int l,int r);
}seg;
void segmentTree::push_up(int x)
{
    int len=tr[x].r-tr[x].l+1;
    if (len>1)tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
    if (tr[x].lazy!=-1)tr[x].sum=tr[x].lazy*len;
}
void segmentTree::push_down(int x)
{
    if (tr[x].lazy==-1)return;
    tr[x<<1|1].lazy=tr[x<<1].lazy=tr[x].lazy;
    push_up(x<<1);
    push_up(x<<1|1);
    tr[x].lazy=-1;
}
void segmentTree::bt(int x,int l,int r)
{
    tr[x]=Node{l,r,0,0};
    if (l==r)return;
    int mid=(l+r)>>1;
    bt(x<<1,l,mid);
    bt(x<<1|1,mid+1,r);
}
void segmentTree::update(int x,int l,int r,int tt)
{
    if (l<=tr[x].l&&tr[x].r<=r)
    {
        tr[x].lazy=tt;
        push_up(x);
        return;
    }
    int mid=(tr[x].l+tr[x].r)>>1;
    push_down(x);
    if (l<=mid)update(x<<1,l,r,tt);
    if (mid<r)update(x<<1|1,l,r,tt);
    push_up(x);
}
int segmentTree::query(int x,int l,int r)
{
    if (l<=tr[x].l&&tr[x].r<=r)return tr[x].sum;
    int mid=(tr[x].l+tr[x].r)>>1,ans=0;
    push_down(x);
    if (l<=mid)ans+=query(x<<1,l,r);
    if (mid<r)ans+=query(x<<1|1,l,r);
    return ans;
}
int segmentTree::ef(int k,int x,int l,int r)
{
    if (l==r)return l;
    int mid=(l+r)>>1;
    int tp=mid-x+1-query(1,x,mid);
    if (tp<k)return ef(k,x,mid+1,r);
    if (tp>=k)return ef(k,x,l,mid);
}
void work()
{
    read(n); read(m);
    seg.bt(1,0,n-1);
    for(int i=1;i<=m;i++)
    {
        int id,x,y;
        read(id); read(x); read(y);
        if (id==1)
        {
            int k=seg.query(1,x,n-1);
            if (k==n-x){printf("Can not put any one.\n");continue;}
            int ds=seg.ef(1,x,x,n-1);
            int dw=seg.ef(min(n-x-k,y),x,x,n-1);
            seg.update(1,ds,dw,1);
            printf("%d %d\n",ds,dw);
        }
        if (id==2)
        {
            printf("%d\n",seg.query(1,x,y));
            seg.update(1,x,y,0);
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("aa.in","r",stdin);
#endif
    int T;
    read(T);
    while(T--)work(),printf("\n");
}

原文地址:https://www.cnblogs.com/mmmqqdd/p/11241145.html

时间: 2024-10-10 13:39:59

HDU 4614 线段树+二分查找的相关文章

hdu 4614 线段树 二分

题意:有n个花瓶,每个花瓶中只能放一朵花. 两种操作,一种是从A开始放F朵花,如果有的花瓶中已经有花则跳过这个花瓶,往下一个花瓶放: 输出这次放的花的左右端点.如果能放但是放不完f朵输出n就好了 第二种是将区间[A,B]之间花瓶中的花清空.输出这次总共清理出了多少支花. 思路:第二种很明显可以用线段树实现,问题在第一种如何用线段树实现 用二分  和 线段树 来判断右端点的位置  这样就可以了  第一次操作就成了区间更新 并且查询左右端点 #include<cstdio> #include<

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 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,每次更新,因为

离散化+线段树/二分查找/尺取法 HDOJ 4325 Flowers

题目传送门 题意:给出一些花开花落的时间,问某个时间花开的有几朵 分析:这题有好几种做法,正解应该是离散化坐标后用线段树成端更新和单点询问.还有排序后二分查找询问点之前总花开数和总花凋谢数,作差是当前花开的数量,放张图易理解: 还有一种做法用尺取法的思想,对暴力方法优化,对询问点排序后再扫描一遍,花开+1,花谢-1.详细看代码. 收获:一题收获很多:1. 降低复杂度可以用二分 2. 线段计数问题可以在端点标记1和-1 3. 离散化+线段树 终于会了:) (听说数据很水?) 代码1:离散化+线段树

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 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 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

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f