线段树二分

线段树二分

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

线段树上二分

题目:2828 -- Buy Tickets (poj.org)

思路:

倒着考虑每个人,就可以确定下每个人的位置了。

比如第n个人,一定在p[n]+1的位置上

思考如何判断第 n-1 个人的位置。

if (p[n-1]+1<p[n]+1) :

​ 第 n-1 个人的位置在 p[n-1]+1 处

else if(p[n-1]+1>=p[n]+1)

​ 第n-1 人的为值往后移动了一位置 在 p[n-1]+2;

总结:

第n-1 个人的位置 ,是除了第 n 个人所在位置以外的 n-1 个位置

第n-1个人的相对位置与第n个人无关

问题转换为 一开始有 n 个位置,每次我们查询从左往右数第 k 个空位置,然后放置一个人(位置变为非空);

[========]

include

include

include

using namespace std;

define ll long long

const int N = 1e6 + 10;
struct node
{
int l, r;
ll sum;
};
struct sgt_tree
{

define ls (u<<1)

define rs (u<<1|1)

node t[N * 8];
void pushup(int u)
{
	t[u].sum = t[ls].sum + t[rs].sum;
}
void build(int u, int l, int r)
{
	t[u].l=l;t[u].r=r;
	if (l == r)
	{
		t[u].sum = 1;
		return;
	}
	int mid = (l + r) >> 1;
	build(ls, l, mid);
	build(rs, mid + 1, r);
	pushup(u);
}
void change(int u, int k,int&p)
{
	if (t[u].l == t[u].r) {
		t[u].sum = 0;
		p = t[u].l;
		return ;
	}
	int mid = (t[u].l + t[u].r) >> 1;
	if (t[ls].sum >= k)change(ls, k,p);
	else change(rs, k - t[ls].sum,p);
	pushup(u);
}

undef ls

undef rs

}sgt;
int n;
int ans[N], pos[N], val[N];
int main()
{
while (~scanf("%d", &n))
{
for (int i = 1; i <= n; i++)scanf("%d%d", &pos[i], &val[i]);
sgt.build(1, 1, n);
for (int i = n; i >= 1; i--)
{
int p; sgt.change(1, pos[i] + 1, p);
ans[p] = val[i];
}
for (int i = 1; i <= n; i++)printf("%d%c", ans[i], (i < n) ? ' ' : '\n');
}
return 0;
}

posted @ 2021-10-06 00:06  warmhearthhh  阅读(101)  评论(0)    收藏  举报