线段树二分

该博客介绍了如何使用线段树数据结构结合二分查找方法,解决一个模拟约会场景的问题。程序中,两个线段树分别维护男生和女生的预约时间段,通过更新和查询操作,实现快速查找合适的约会时间。查询分为三种情况,并提供了相应的处理逻辑。此外,还展示了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

线段树二分

Problem - 4553 (hdu.edu.cn)

用2个线段树分别维护男生预约的时间段和女生预约的时间段。

线段树里面保存的是最大连续子段和,空闲时间为1,预约了的话就是0。
当男生来预约的时候,只需要修改男生的线段树即可。 而当女生来预约的时候若在男生的线段树里面找不到空闲时间再去女生线段树里面查找,若找到就修改男生和女生2个线段树(因为女生可以无视基友)。
每次查询修改时候进行区间下放。
查询的时候分成3种情况,首先如果调用查询函数代表一定有那么多空闲时间。
1.在左区间
2.左边区间和右边区间合并得来的答案,这种情况直接返回这个区间的左端点即可。
3.在右区间

#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 2e6 + 10;
struct tnode
{
    int l, r;
    int lazy;
    int lmx, rmx, ans;//最大子段和
    tnode friend operator +(tnode a, tnode b)
    {
        tnode res;
        res.l = a.l;
        res.r = b.r;
        res.lazy=-1;
        res.lmx = a.lmx + (a.lmx == (a.r - a.l + 1) ? b.lmx : 0);
        res.rmx = b.rmx + (b.rmx == (b.r - b.l + 1) ? a.rmx : 0);
        res.ans = max(max(a.ans, b.ans), max(res.lmx, res.rmx));
        res.ans=max(res.ans,a.rmx+b.lmx);
        return res;
    }
};
int n, m;
struct segment_tree
{
#define lch (root<<1)
#define rch (root<<1|1)
#define mid (t[root].l+t[root].r>>1)
    tnode t[MAXN<<2];
    void pushup(int root)
    {
        t[root] = t[lch] + t[rch];
    }
    void pushdown(int root)
    {
        if (t[root].lazy == -1)return;
        t[lch].lazy = t[root].lazy;
        t[lch].lmx = t[lch].rmx = t[lch].ans =(t[lch].r - t[lch].l + 1) * t[root].lazy;

        t[rch].lazy = t[root].lazy;
        t[rch].lmx = t[rch].rmx = t[rch].ans =(t[rch].r - t[rch].l + 1) * t[root].lazy;

        t[root].lazy = -1;
    }
    void build(int root, int l, int r)
    {
        t[root].l = l;
        t[root].r = r;
        t[root].lazy = -1;
        if (l == r) {
            t[root].lmx = t[root].rmx = t[root].ans =1;
            return;
        }
        build(lch, l, mid);
        build(rch, mid + 1, r);
        pushup(root);
    }
    void fugai(int root, int ql, int qr, int v)
    {
        if (t[root].l > qr || t[root].r < ql)return;
        if (t[root].l >= ql && t[root].r <= qr)
        {
            t[root].lazy = v;
            t[root].lmx = t[root].rmx = t[root].ans = (t[root].r - t[root].l + 1) * v;
            return;
        }
        pushdown(root);
        fugai(lch, ql, qr, v);
        fugai(rch, ql, qr, v);
        pushup(root);
    }
    void ask(int root,int len,int &res)
    {
       if(t[root].l==t[root].r){res=min(t[root].l,res);return;}
        pushdown(root);
       if(t[lch].ans>=len)ask(lch,len,res);
       else if(t[lch].rmx+t[rch].lmx>=len)res=min(res,(mid-t[lch].rmx+1));
       else if(t[rch].ans>=len)ask(rch,len,res);
       pushup(root);
       return;
    }
    int ask(int root,int len)
    {
        if(t[root].l==t[root].r)return t[root].l;
        pushdown(root);
        if(t[lch].ans>=len)return ask(lch,len);
        else if(t[lch].rmx+t[rch].lmx>=len)return mid-t[lch].rmx+1;
        else return ask(rch,len);
    }
#undef lch
#undef rch
#undef mid
}man,weman;
int main()
{

   int T;
    scanf("%d", &T);
    for (int ci = 1; ci <= T; ci++) {
        scanf("%d%d", &n, &m);
        man.build(1, 1, n);
        weman.build(1, 1, n);
        printf("Case %d:\n", ci);


        for (int i = 1; i <= m; i++) {
            char s[33];
            int x,y;

            scanf("%s%d", s, &x);
            if (s[0] == 'D') {
                if (man.t[1].ans >= x) {
                    int t=man.ask(1,x);
                    man.fugai(1,t,t+x-1,0);
                    printf("%d,let's fly\n", t);
                }
                else {
                    printf("fly with yourself\n");
                }
            }
            else if (s[0] == 'N') {
                if (man.t[1].ans >= x) {
                    int t=man.ask(1,x);
                    man.fugai(1,t,t+x-1,0);
                    weman.fugai(1,t,t+x-1,0);
                    printf("%d,don't put my gezi\n", t);
                }
                else if (weman.t[1].ans >= x) {
                    int t=weman.ask(1,x);

                    weman.fugai(1,t,t+x-1,0);
                    man.fugai(1,t,t+x-1,0);
                    printf("%d,don't put my gezi\n", t);
                }
                else {
                    printf("wait for me\n");
                }
            }
            else {
                scanf("%d", &y);
                man.fugai(1,x,y,1);
                weman.fugai(1,x,y,1);
                printf("I am the hope of chinese chengxuyuan!!\n");
            }

        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值