约会安排---hdu4553(线段树,麻烦的区间覆盖)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4553

算是poj3667的加强版,建立两颗线段树,一个是DS区间,另一个是NS区间。那么根据题意,如果是DS的请求,那么首先查找DS的区间,如果有满足的区间就更新DS区间,NS的区间不需要更新。如果是NS的请求,首先看DS区间是否有满足的区间,否则查找NS区间,如果有就同时更新DS区间和NS区间。那么可以归纳为,只要是NS的请求,就同时更新两颗线段树,否则只更新DS的线段树。

注意输出要从Output中复制,不然会wa道底,还有就是Up函数中的if顺序不能变;

这两道题写了一天,不过值了,当然如果不是因为有学长的博客在,我一天根本写不出来,学长毕竟是学长;

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

#define INF 0xfffffff
#define N 110050
#define Lson r<<1
#define Rson r<<1|1

struct SegmentTree
{
    int L, R;
    bool ns, ds, study;  ///0代表
    int lsum[2], rsum[2], sum[2];  ///0是屌丝,1女神;

    ///lsum区间左边(从L开始)连续最大不被覆盖的值
    ///rsum区间右边(到R介绍)连续最大不被覆盖的值
    ///sum整个区间连续最大不被覆盖的值

    int Mid() { return (L+R)>>1;}
    int len() { return R-L+1; }

    void clearPlan(bool x)///清空;
    {
        if(x)
        {
            lsum[0] = lsum[1] = len();
            rsum[0] = rsum[1] = len();
            sum[0] = sum[1] = len();
            ns = ds = false; study = true;
        }
    }

    void NS(bool x)///女神;
    {
        if(x)
        {
            lsum[0] = lsum[1] = 0;
            rsum[0] = rsum[1] = 0;
            sum[0] = sum[1] = 0;
            ns = true; ds = false;
        }
    }
    void DS(bool x)///屌丝;
    {
        if(x)
        {
            lsum[0] = rsum[0] = sum[0] = 0;
            ds = true;
        }
    }
} a[N<<2];

void Build(int r, int L, int R)
{
    a[r].L = L, a[r].R = R;
    a[r].clearPlan(true);///清空 ;
    a[r].ns = a[r].ds = a[r].study = false;

    if(L == R)return ;

    Build(Lson, L, a[r].Mid());
    Build(Rson, a[r].Mid()+1, R);
}

void Up(int r, int who)
{
    if(a[r].L != a[r].R)
    {
        a[r].lsum[who] = a[Lson].lsum[who];
        a[r].rsum[who] = a[Rson].rsum[who];

        if(a[Lson].lsum[who] == a[Lson].len())
            a[r].lsum[who] += a[Rson].lsum[who];
        if(a[Rson].rsum[who] == a[Rson].len())
            a[r].rsum[who] += a[Lson].rsum[who];

        a[r].sum[who] = max(a[Lson].rsum[who] + a[Rson].lsum[who],
                             max(a[Lson].sum[who], a[Rson].sum[who]));
    }
}

void Down(int r)///这个顺序不能反
{
    if(a[r].study)
    {
        a[Lson].clearPlan(true);
        a[Rson].clearPlan(true);
        a[r].study = false;
    }
    if(a[r].ns)
    {
        a[Lson].NS(true);
        a[Rson].NS(true);
        a[r].ns = a[r].ds = false;
    }
    if(a[r].ds)
    {
        a[Lson].DS(true);
        a[Rson].DS(true);
        a[r].ds = false;
    }
}

void Update(int r, int L, int R, int flag)
{
    if(a[r].L == L && a[r].R == R)
    {
        if(flag == 3) a[r].DS(true);
        if(flag == 2) a[r].NS(true);
        if(flag == 1) a[r].clearPlan(true);

        return;
    }

    Down(r);

    if( R <= a[r].Mid())
        Update(Lson, L, R, flag);
    else if( L > a[r].Mid())
        Update(Rson, L, R, flag);
    else
    {
        Update(Lson, L, a[r].Mid(), flag);
        Update(Rson, a[r].Mid()+1, R, flag);
    }
    Up(r, 0);
    Up(r, 1);
}

int Query(int r, int num, int who)
{
    Down(r);

    if(a[r].sum[who] < num) return 0;

    if(a[r].lsum[who] >= num) return a[r].L;
    if(a[Lson].sum[who] >= num) return Query(Lson, num, who);

    if(a[Lson].rsum[who]+a[Rson].lsum[who] >= num)
        return a[Lson].R - a[Lson].rsum[who] + 1;
    return Query(Rson, num, who);
}

int main()
{
    int n, m, T, t = 1, R, L, time;

    scanf("%d", &T);
    while(T--)
    {
        scanf("%d %d", &n, &m);
        Build(1, 1, n);

        printf("Case %d:\n", t++);
        while(m--)
        {
            char s[1100];
            scanf("%s", s);
            if(s[0] == ‘D‘)
            {
                scanf("%d", &time);
                L = Query(1, time, 0);///屌丝是0;

                if( !L )printf("fly with yourself\n");
                else
                {
                    Update(1, L, L+time-1, 3);
                    printf("%d,let‘s fly\n", L);
                }
            }
            else if(s[0] == ‘N‘)
            {
                scanf("%d", &time);

                L = Query(1, time, 0);///先在屌丝时间里找;当在屌丝时间里没时间时在女神时间里找;
                if( !L ) L = Query(1, time, 1);///女神是1;

                if( !L )printf("wait for me\n");
                else
                {
                    Update(1, L, L+time-1, 2);
                    printf("%d,don‘t put my gezi\n", L);
                }
            }
            else
            {
                scanf("%d %d", &L, &R);
                Update(1, L, R, 1);
                printf("I am the hope of chinese chengxuyuan!!\n");
            }
        }
    }
    return 0;
}

时间: 2024-10-27 13:06:10

约会安排---hdu4553(线段树,麻烦的区间覆盖)的相关文章

算法模板——线段树3(区间覆盖值+区间求和)

实现功能——1:区间覆盖值:2:区间求和 相比直接的区间加,这个要注重顺序,因为操作有顺序之分.所以这里面的tag应该有个pushup操作(本程序中的ext) 1 var 2 i,j,k,l,m,n,a1,a2,a3,a4:longint; 3 a,b,d:array[0..100000] of longint; 4 function max(x,y:longint):longint;inline; 5 begin 6 if x>y then max:=x else max:=y; 7 end;

HDOJ--4893--Wow! Such Sequence!【线段树+单点、区间更新】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 题意:给你一个长度n的数列,初始都为0,有三种操作,第一种给第k个位置的数加d,第二种是查询区间 [l , r] 的总和,第三种是使区间 [l , r] 的值改为离它最近的那个斐波那契数的值. 我刚开始用sum数组存储节点的值,第三种操作是个区间更新,但是区间更新的值不一样,我就想当然的搜到最底部的节点来处理更新,果断T了.后来想了想,其实可以在节点上再加一个信息,就是这个值下次进行第三种操作要变

线段树2 求区间最小值

线段树2 求区间最小值 从数组arr[0...n-1]中查找某个数组某个区间内的最小值,其中数组大小固定,但是数组中的元素的值可以随时更新. 数组[2, 5, 1, 4, 9, 3]可以构造如下的二叉树(背景为白色表示叶子节点,非叶子节点的值是其对应数组区间内的最小值,例如根节点表示数组区间arr[0...5]内的最小值是1): 线段树的四种操作: 1.线段树的创建 2.线段树的查询 3.线段树的更新单节点 4.线段树的更新区间 直接上完整代码吧 1 #include <bits/stdc++.

UPC 2224 Boring Counting (离线线段树,统计区间[l,r]之间大小在[A,B]中的数的个数)

题目链接:http://acm.upc.edu.cn/problem.php?id=2224 题意:给出n个数pi,和m个查询,每个查询给出l,r,a,b,让你求在区间l~r之间的pi的个数(A<=pi<=B,l<=i<=r). 参考链接:http://www.cnblogs.com/zj62/p/3558967.html #include <iostream> #include <cstdio> #include <cstring> #incl

hdu - 4973 - A simple simulation problem.(线段树单点更新 + 区间更新)

题意:初始序列 1, 2, ..., n,m次操作(1 <= n,m<= 50000),每次操作可为: D l r,将区间[l, r]中的所有数复制一次: Q l r,输出区间[l, r]中同一数字个数的最大值. (0 <= r – l <= 10^8, 1 <= l, r <= 序列元素个数) 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4973 -->>因为区间内数字是依次递增的,所以可以以数字为叶建线段

【HDU】1754 I hate it ——线段树 单点更新 区间最值

I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 37448    Accepted Submission(s): 14816 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少.这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要

hdu 3308 线段树单点更新 区间合并

http://acm.hdu.edu.cn/showproblem.php?pid=3308 学到两点: 1.以区间端点为开始/结束的最长......似乎在Dp也常用这种思想 2.分类的时候,明确标准逐层分类,思维格式: 条件一成立: { 条件二成立: { } else { } } else { 条件二成立: { } else { } } 上面的这种方式很清晰,如果直接想到那种情况iif(条件一 &条件二)就写,很容易出错而且把自己搞乱,或者情况不全,,,我就因为这WA了几次 3.WA了之后 ,

hdu2795(线段树单点更新&amp;区间最值)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795 题意:有一个 h * w 的板子,要在上面贴 n 条 1 * x 的广告,在贴第 i 条广告时要尽量将其靠上贴,并输出其最上能贴在哪个位置: 思路:可以将每行剩余空间大小存储到一个数组中,那么对于当前 1 * x 的广告,只需找到所有剩余空间大于的 x 的行中位置最小的即可: 不过本题数据量为 2e5,直接暴力因该会 tle.可以用个线段树维护一下区间最大值,然后查询时对线段树二分即可: 代码

POJ 3468 A Simple Problem with Integers(线段树模板之区间增减更新 区间求和查询)

A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 140120   Accepted: 43425 Case Time Limit: 2000MS Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type o