HDU 4553 约会安排 [线段树]

http://acm.hdu.edu.cn/showproblem.php?pid=4553
题意:有个屌丝有T的空闲时间。每次有人与他约t的时间,他都会找到最靠前的一段符合要求的时间,称为“最先适应算法”。
1,如果基友约他,他就会按“最先适应算法”去找,找到就约否则不约。
2,如果女神约他,他也会先按原先的方法去找,如果找不到,那他会忽略所有与基友的约定而通过原来的方法去找跟女神约会的时间,找到就约否则不约。
3,有时他会脑抽,选择一个区间 [l,r] ,将该区间的安排都清空。

思路:
可以用两棵线段树去维护这段时间,一棵维护全部的安排,一棵只维护和女神的安排。若基友来约,则直接从全部安排中找时间,若女神来约,则先从全部的找,找不到再从另一棵中找(相当于忽略了基友)。

接下来说怎么找空闲时间:
用1表示空闲0表示有安排。
left[i] 表示 i 结点对应区间 [L,R] 中左连续最长空闲时间, right[i] 表示右连续最长空闲时间, middle[i] 表示横跨该结点左右子结点的最长连续空闲时间, maxlen[i] 表示该结点表示区间中的最长空闲时间

对于询问 t,按以下顺序判断:
maxlen[i]<t 则此结点无解。
left[i]t ,则返回 L (空闲时段起点)
maxlen[lc]t,则向左子树递归,返回其结果。
middle[i]t ,则返回 midright[lc]+1 ,即跨左右子树的起点。
否则 向右子树递归,返回其结果。

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

#define rep(i,f,t) for(int i = (f),_end = (t);  i <= _end; ++i)
#define MID int mid = (L+R)>>1;
#define CHD int lc = node<<1, rc = node<<1|1;

const int maxn = 100001<<2;

struct sgt{
    int maxlen[maxn];
    int left[maxn], middle[maxn], right[maxn];
    int setv[maxn];
    void init(){
        setv[1] = 1;
    }
    void maintain(int node,int L,int R){
        if(setv[node] >= 0){
            maxlen[node] = left[node] = right[node] = middle[node] = 
                (setv[node] ? (R-L+1) : 0);
        } else {
            CHD;MID;
            left[node] = left[lc];
            if(left[lc]==(mid-L+1)) left[node] += left[rc];
            middle[node] = right[lc]+left[rc];
            right[node] = right[rc];
            if(right[rc]==R-mid)    right[node] += right[lc];
            maxlen[node] = max(max(maxlen[lc],maxlen[rc]),middle[node]);
        }
    }
    void pushDown(int node){
        if(setv[node] >= 0){
            CHD;
            setv[lc] = setv[rc] = setv[node];
            setv[node] = -1;
        }
    }

    int query(int val,int node,int L,int R){
        maintain(node,L,R);
        if(val > maxlen[node])return 0; //不在此结点上
        if(left[node] >= val)return L;  //left
        MID;CHD;
        pushDown(node);
        maintain(rc,mid+1,R); //先维护好右结点信息,方便直接返回
        int tmp;
        if((tmp=query(val,lc,L,mid))) return tmp; //leftmax
        if(middle[node] >= val) return mid-right[lc]+1; //middle
        return query(val,rc,mid+1,R); //肯定在右结点上
    }

    void update(int from,int to,int val,int node,int L,int R){
        if(from <= L && R <= to){
            setv[node] = val;
        }else{
            pushDown(node);
            MID;CHD;
            if(from <= mid) update(from,to,val,lc,L,mid);
            else    maintain(lc,L,mid);
            if(to > mid) update(from,to,val,rc,mid+1,R);
            else    maintain(rc,mid+1,R);
        }
        maintain(node,L,R);
    }
}ns,all;

int main(){
    int T;
    scanf("%d",&T);
    rep(cas,1,T){
        int n,m;
        scanf("%d%d",&n,&m);
        ns.init();all.init();
        printf("Case %d:\n",cas);
        while(m--){
            char s[10];int a,b;
            int ans;
            scanf("%s",s);
            switch(s[0]){
                case 'N':
                    scanf("%d",&a);
                    if((ans=all.query(a,1,1,n))||(ans=ns.query(a,1,1,n))){
                        all.update(ans,ans+a-1,0,1,1,n);
                        ns.update(ans,ans+a-1,0,1,1,n);
                        printf("%d,don\'t put my gezi\n",ans);
                    } else {
                        printf("wait for me\n");
                    }
                    break;
                case 'D':
                    scanf("%d",&a);
                    ans = all.query(a,1,1,n);
                    if(ans){
                        all.update(ans,ans+a-1,0,1,1,n);
                        printf("%d,let\'s fly\n",ans);
                    }else{
                        printf("fly with yourself\n");
                    }
                    break;
                case 'S':
                    scanf("%d%d",&a,&b);
                    all.update(a,b,1,1,1,n);
                    ns.update(a,b,1,1,1,n);
                    printf("I am the hope of chinese chengxuyuan!!\n");
                    break;
            }
        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

转载于:https://www.cnblogs.com/DSChan/p/4861977.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值