HDU 4553 约会安排(线段树维护区间最大连续长度)

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

解题思路:


①题目的意思是询问当前是否能够给出空余的一段连续时间,并且这段时间尽可能靠前

需要两棵树,一棵屌丝+女神,另一棵女神

对于屌丝询问第一棵树有无这样一段连续时间,有就更新第一棵树,没有就不约

对于女神先询问第一棵树,第一棵树有就约会,如果第一棵树没有符合的区间,查询第二棵树有就约。最后更新两棵树对应求出的区间。

还有一个清空操作,清空两棵树对应区间即可。


②因为两棵树模式一样,分析一棵就行了。

如何才能查找到区间内最靠左的符合条件的区间呢?

肯定要利用DFS的性质,让搜索可以“可以左就先左,左到不能再搜右”

让线段树维护区间最长连续长度,以及从左往右,从右往左的最长连续长度。

现在我们假设线段树已经维护了这些东西,再假设需要一段长度为x的时间,那么:

如果(if)左子树的最长连续长度>=x,那么就搜左子树

否则如果(else if)看左子树右到左+右子树左到右>=z,那么更新一次这里的答案

再否则如果(else if)右子树最长连续长度>=x,搜右子树

按照这样的思路搜索,尽量让答案向左靠近


③如果不清楚维护区间连续最大和的方法请看代码中的push_up()函数

#define dl ds[rt<<1]
#define dr ds[rt<<1|1]

void push_up(int rt,T ds[])
{
    ds[rt].l = (dl.l==dl.len)? dl.len+dr.l : dl.l;
    ds[rt].r = (dr.r==dr.len)? dr.len+dl.r : dr.r;
    ds[rt].ans = max(max(dl.ans,dr.ans),dl.r+dr.l);
}

l表示左到右最大连续,r表示右到左最大连续,ans表示区间最大连续


④然后因为都是区间修改,那么就要涉及push_down()也就是下放函数了。

由于区间要么整体清0,要么整体全1,所以在区间和等于0,或者等于区间长度时,下放就可以了。只有这两种情况是修改到这一层没继续下更新的情况。


⑤query函数if(l==r)的判断很重要,不然叶子下放直接GG(奥义之无限RE别问我为什么要提醒你)


代码1(愚蠢加长版):

#include
#include
#include
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define dl ds[rt<<1]
#define dr ds[rt<<1|1]
#define nl ns[rt<<1]
#define nr ns[rt<<1|1]

using namespace std;

const int N = 1e5+5;

struct T
{
    int l,r,len,ans;
}ds[N<<2],ns[N<<2];

int ans;

void push_up(int rt,int op)
{
     if (op==1){
        ds[rt].l = (dl.l==dl.len)? dl.len+dr.l : dl.l;
        ds[rt].r = (dr.r==dr.len)? dr.len+dl.r : dr.r;
        ds[rt].ans = max(max(dl.ans,dr.ans),dl.r+dr.l);
     }
     else {
        ns[rt].l = (nl.l==nl.len)? nl.len+nr.l : nl.l;
        ns[rt].r = (nr.r==nr.len)? nr.len+nl.r : nr.r;
        ns[rt].ans = max(max(nl.ans,nr.ans),nl.r+nr.l);
     }
}

void push_down(int rt,int op)///区间0,区间1
{
    if (op==1){
        if (ds[rt].ans == 0){
            dl.l = dl.r = dr.l = dr.r = dl.ans = dr.ans = 0;
        }
        if (ds[rt].ans == ds[rt].len){
            int len = ds[rt].len;
            dl.ans = dl.l = dl.r = (len-len/2);
            dr.ans = dr.l = dr.r = len/2;
        }
    }
    else {
        if (ns[rt].ans == 0){
            nl.l = nl.r = nr.l = nr.r = nl.ans = nr.ans = 0;
        }
        if (ns[rt].ans == ns[rt].len){
            int len = ns[rt].len;
            nl.ans = nl.l = nl.r = (len-len/2);
            nr.ans = nr.l = nr.r = len/2;
        }
    }
}

void query(int x,int op,int rt,int l,int r)
{
    if (l==r){
        ans = min(ans,l);
        return ;
    }
    mid;
    push_down(rt,op);
    if (op==1){
        if (dl.ans >= x)    query(x,op,lson);
        else if (dl.r+dr.l >= x) ans = min(ans,m-dl.r+1);
        else if (dr.ans >= x)    query(x,op,rson);
    }
    if (op==2){
        if (nl.ans >= x)    query(x,op,lson);
        else if (nl.r+nr.l >= x) ans = min(ans,m-nl.r+1);
        else if (nr.ans >= x)    query(x,op,rson);
    }
}

void update(int L,int R,int x,int op,int rt,int l,int r)
{
    if (L<=l && r<=R){
        if (op==1){
            if (x==0) ds[rt].ans = ds[rt].l = ds[rt].r = 0;
            else ds[rt].ans = ds[rt].l = ds[rt].r = r-l+1;
        }
        if (op==2){
            if (x==0) ns[rt].ans = ns[rt].l = ns[rt].r = 0;
            else ns[rt].ans = ns[rt].l = ns[rt].r = r-l+1;
        }
        return ;
    }
    mid;
    push_down(rt,op);
    if (L<=m) update(L,R,x,op,lson);
    if (R>m)  update(L,R,x,op,rson);
    push_up(rt,op);
}

void build(int rt,int l,int r)
{
    if (l==r){
        ds[rt].ans = ds[rt].l = ds[rt].r = ds[rt].len = 1;
        ns[rt].ans = ns[rt].l = ns[rt].r = ns[rt].len = 1;
        return ;
    }
    mid;
    build(lson);
    build(rson);
    push_up(rt,1);
    push_up(rt,2);
    ds[rt].len = dl.len + dr.len;
    ns[rt].len = nl.len + nr.len;
}

int main()
{
    int T,n,m;
    scanf("%d",&T);
    int kca = 1;
    while (T--){
        printf("Case %d:\n",kca++);
        scanf("%d %d",&n,&m);
        build(1,1,n);
        char op[10];
        int l,r,len;
        while (m--){
            scanf("%s",op);
            if (op[0]=='S'){
                scanf("%d %d",&l,&r);
                printf("I am the hope of chinese chengxuyuan!!\n");
                update(l,r,1,1,1,1,n);
                update(l,r,1,2,1,1,n);
            }
            else {
                scanf("%d",&len);
                ans = n*2;///初始化为一个很大的数
                if (op[0]=='D'){
                    query(len,1,1,1,n);
                    if (ans==n*2) printf("fly with yourself\n");
                    else {
                        printf("%d,let's fly\n",ans);
                        update(ans,ans+len-1,0,1,1,1,n);
                    }
                }
                else {
                    query(len,1,1,1,n);
                    if (ans==n*2) query(len,2,1,1,n);
                    if (ans==n*2) printf("wait for me\n");
                    else {
                        printf("%d,don't put my gezi\n",ans);
                        update(ans,ans+len-1,0,1,1,1,n);
                        update(ans,ans+len-1,0,2,1,1,n);
                    }
                }
            }
        }
    }
    return 0;
}

代码2(略微精简版):

#include
#include
#include
#define ll long long
#define lson rt<<1,l,m
#define rson rt<<1|1,m+1,r
#define mid int m=l+r>>1
#define dl ds[rt<<1]
#define dr ds[rt<<1|1]
#define nl ns[rt<<1]
#define nr ns[rt<<1|1]

using namespace std;

const int N = 1e5+5;

struct T
{
    int l,r,len,ans;
}ds[N<<2],ns[N<<2];

int ans;

void push_up(int rt,T ds[])
{
    ds[rt].l = (dl.l==dl.len)? dl.len+dr.l : dl.l;
    ds[rt].r = (dr.r==dr.len)? dr.len+dl.r : dr.r;
    ds[rt].ans = max(max(dl.ans,dr.ans),dl.r+dr.l);
}

void push_down(int rt,T ds[])
{
    if (ds[rt].ans == 0){
        dl.l = dl.r = dr.l = dr.r = dl.ans = dr.ans = 0;
    }
    if (ds[rt].ans == ds[rt].len){
        int len = ds[rt].len;
        dl.ans = dl.l = dl.r = (len-len/2);
        dr.ans = dr.l = dr.r = len/2;
    }
}

void query(int x,T ds[],int rt,int l,int r)
{
    if (l==r){
        ans = min(ans,l);
        return ;
    }
    mid;
    push_down(rt,ds);
    if (dl.ans >= x)    query(x,ds,lson);
    else if (dl.r+dr.l >= x) ans = min(ans,m-dl.r+1);
    else if (dr.ans >= x)    query(x,ds,rson);
}

void update(int L,int R,int x,T ds[],int rt,int l,int r)
{
    if (L<=l && r<=R){
        if (x==0) ds[rt].ans = ds[rt].l = ds[rt].r = 0;
        else ds[rt].ans = ds[rt].l = ds[rt].r = r-l+1;
        return ;
    }
    mid;
    push_down(rt,ds);
    if (L<=m) update(L,R,x,ds,lson);
    if (R>m)  update(L,R,x,ds,rson);
    push_up(rt,ds);
}

void build(int rt,int l,int r)
{
    if (l==r){
        ds[rt].ans = ds[rt].l = ds[rt].r = ds[rt].len = 1;
        ns[rt].ans = ns[rt].l = ns[rt].r = ns[rt].len = 1;
        return ;
    }
    mid;
    build(lson);
    build(rson);
    push_up(rt,ds);
    push_up(rt,ns);
    ds[rt].len = dl.len + dr.len;
    ns[rt].len = nl.len + nr.len;
}

int main()
{
    int T,n,m;
    scanf("%d",&T);
    int kca = 1;
    while (T--){
        printf("Case %d:\n",kca++);
        scanf("%d %d",&n,&m);
        build(1,1,n);
        char op[10];
        int l,r,len;
        while (m--){
            scanf("%s",op);
            if (op[0]=='S'){
                scanf("%d %d",&l,&r);
                printf("I am the hope of chinese chengxuyuan!!\n");
                update(l,r,1,ds,1,1,n);
                update(l,r,1,ns,1,1,n);
            }
            else {
                scanf("%d",&len);
                ans = n*2;///初始化为一个很大的数
                if (op[0]=='D'){
                    query(len,ds,1,1,n);
                    if (ans==n*2) printf("fly with yourself\n");
                    else {
                        printf("%d,let's fly\n",ans);
                        update(ans,ans+len-1,0,ds,1,1,n);
                    }
                }
                else {
                    query(len,ds,1,1,n);
                    if (ans==n*2) query(len,ns,1,1,n);
                    if (ans==n*2) printf("wait for me\n");
                    else {
                        printf("%d,don't put my gezi\n",ans);
                        update(ans,ans+len-1,0,ds,1,1,n);
                        update(ans,ans+len-1,0,ns,1,1,n);
                    }
                }
            }
        }
    }
    return 0;
}

总结:

目前做到的维护区间连续的题目有三道:(题解都有写)

HDU 1540

Vijos 1083

以及这一题。

维护区间连续也是线段树一大功能啊。

其中的精髓就是通过区间合并得出任意区间对应的信息。

基本上涉及到区间连续性就要用这个思路啦。一左一右一整体。

不过这题的思路感觉还是比较清奇,应该是   利用DFS+线段树维护连续性。 

你可能感兴趣的:(HDU 4553 约会安排(线段树维护区间最大连续长度))