HDU 4553 线段树连续区间

本文深入探讨了线段树在解决特定类型问题时的应用技巧,包括如何高效地更新连续区间和查询最大连续区间长度等核心操作。通过实例分析,展示了线段树在处理区间更新与查询任务时的优势。

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

题意

中文题,不解释

题解

线段树真的是一题一世界啊。。刚开始的时候想到的并不是连续区间。以前有一道题也是找位置,修改点,但是允许非连续区间。那道题用的是二分。这道题原本也想用二分,但是一方面实现起来比较困难,另一方面即便真的实现了,在时间复杂度上也存在很大的问题。
因为必须要找一块连续的区间去做事情,所以说这道题完全不需要二分去找起始和终止位置。只需要维护连续区间长度就可以了,如果连续区间长度小于需要长度,则返回0,并输出相应字符。如果连续区间长度大于需要长度,找到第一个大于需要长度的连续区间,返回左边界。从左边界开始执行Update就可以了。
需要注意的是,题目中的修改存在优先级,高优先级的修改可以完全无视低优先级的修改。在这里,由于优先级等级比较少,可以使用两棵线段树进行维护。

注意事项

线段树本身就有很多需要注意的地方。首先的话,在实现上,一定要注意pushdown之后不能直接修改成0,原因很简单,因为setv可以为0。如果直接修改成0的话,在query的时候就会出错。(因此,大多数情况下,setv初始值设置为-1比较稳妥)

代码

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#include<stack>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f3f3f3f3f
#define LL long long
#define MAXN 120010
#define SIZE 95
#define EPS 1e-10
#define MOD 1000000007

using namespace std;

struct Node {
    int left,right,mid;
    int maxlen;
};

int lt,rt,v,len;
char ch[10];

struct Tree {
    Node nodes[MAXN<<2];
    int setv[MAXN<<2];
    void init() {
        MEM(setv,-1);
        MEM(nodes,0);
        setv[1]=1;
    }
    void maintain(int o,int l,int r) {
        if(setv[o]>=0) {
            nodes[o].maxlen=nodes[o].left=nodes[o].right=nodes[o].mid=setv[o]!=0?(r-l+1):0;
        }else if(l==r) {
            nodes[o].maxlen=nodes[o].left=nodes[o].right=nodes[o].mid=0;
        } else {
            int mid=l+(r-l)/2;
            nodes[o].left=nodes[o*2].left;
            if(nodes[o].left==(mid-l+1)) {
                nodes[o].left+=nodes[o*2+1].left;
            }
            nodes[o].right=nodes[o*2+1].right;
            if(nodes[o].right==(r-mid)) {
                nodes[o].right+=nodes[o*2].right;
            }
            nodes[o].mid=nodes[o*2].right+nodes[o*2+1].left;
            nodes[o].maxlen=max(max(nodes[o*2].maxlen,nodes[o*2+1].maxlen),nodes[o].mid);
        }
    }
    void pushdown(int o) {
        if(setv[o]>=0) {
            setv[o*2]=setv[o*2+1]=setv[o];
        }
        setv[o]=-1;
    }
    void update(int o,int l,int r) {
        if(lt<=l&&rt>=r) {
            setv[o]=v;
        } else {
            pushdown(o);
            int m=l+(r-l)/2;
            if(lt<=m) {
                update(o*2,l,m);
            } else {
                maintain(o*2,l,m);
            }
            if(rt>m) {
                update(o*2+1,m+1,r);
            } else {
                maintain(o*2+1,m+1,r);
            }
        }
        maintain(o,l,r);
    }

    int query(int o,int l,int r) {
        if(setv[o]>=0) {
            if((r-l+1)>=len) {
                return l;
            } else {
                return 0;
            }
        } else if(l==r) {
            return 0;
        } else {
            if(nodes[o].maxlen<len){
                return 0;
            }
            int m=l+(r-l)/2;
            if(nodes[o*2].maxlen>=len) {
                return query(o*2,l,m);
            } else if(nodes[o].mid>=len) {
                return m-nodes[o*2].right+1;
            } else {
                return query(o*2+1,m+1,r);
            }
        }
    }
} ns,all;

int main() {
    int kase;
    scanf("%d",&kase);
    int ks=1;
    W(kase--) {
        printf("Case %d:\n",ks++);
        int n,t;
        scanf("%d%d",&n,&t);
        ns.init();
        all.init();
        W(t--) {
            scanf("%s",ch);
            int temp;
            if(strcmp(ch,"DS")==0) {
                scanf("%d",&len);
                if(temp=(all.query(1,1,n))) {
                    lt=temp;
                    rt=temp+len-1;
                    v=0;
                    all.update(1,1,n);
                    printf("%d,let's fly\n",lt);
                } else {
                    puts("fly with yourself");
                }
            } else if(strcmp(ch,"NS")==0) {
                scanf("%d",&len);
                if((temp=(all.query(1,1,n)))||(temp=(ns.query(1,1,n)))) {
                    lt=temp;
                    rt=temp+len-1;
                    v=0;
                    all.update(1,1,n);
                    ns.update(1,1,n);
                    printf("%d,don't put my gezi\n",lt);
                } else {
                    puts("wait for me");
                }
            } else if(strcmp(ch,"STUDY!!")==0) {
                scanf("%d%d",&lt,&rt);
                v=1;
                all.update(1,1,n);
                ns.update(1,1,n);
                puts("I am the hope of chinese chengxuyuan!!");
            }
        }
    }
}

/*
10
5 6
DS 3
NS 2
NS 4
STUDY!! 5 5
DS 4
NS 2
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值