HDU 1540(线段树+区间合并)学习记录

学习了线段树的新姿势,记录一下

参考blog:https://blog.csdn.net/sunyutian1998/article/details/79618316

query的时候m-ql+1和qr-m写成了m-l+1、r-m,wa了几发之后才找到bug

错误样例:

10 1
Q 5

wrong answer:5

顺带一提,这个题目可以在set上面二分直接过,不过最主要还是为了练习区间合并

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e4+5;
struct node
{
    int ll,rr,mm;
} tr[4*maxn];
#define lson o*2
#define rson o*2+1
#define m (l+r)/2
inline void pushup(int o,int l,int r)
{
    tr[o].ll=tr[lson].ll;
    tr[o].rr=tr[rson].rr;
    if(tr[o].ll==m-l+1)
        tr[o].ll+=tr[rson].ll;
    if(tr[o].rr==r-m)
        tr[o].rr+=tr[lson].rr;
    tr[o].mm=max(tr[lson].rr+tr[rson].ll,max(tr[lson].mm,tr[rson].mm));
}
void build(int o,int l,int r)
{
    if(l==r)
    {
        tr[o].ll=tr[o].rr=tr[o].mm=1;
        return;
    }
    build(lson,l,m);
    build(rson,m+1,r);
    pushup(o,l,r);
}
void update(int o,int l,int r,int k,int flag)
{
    if(l==r)
    {
        tr[o].ll=tr[o].rr=tr[o].mm=flag;
        return;
    }
    if(k<=m) update(lson,l,m,k,flag);
    else update(rson,m+1,r,k,flag);
    pushup(o,l,r);
}
int query(int o,int l,int r,int ql,int qr,int flag)
{
    if(ql<=l&&qr>=r)
    {
        if(flag==1) return tr[o].ll;
        else return tr[o].rr;
    }
    if(qr<=m) return query(lson,l,m,ql,qr,flag);
    if(ql>m) return query(rson,m+1,r,ql,qr,flag);
    else
    {
        int pl=query(lson,l,m,ql,qr,flag);
        int pr=query(rson,m+1,r,ql,qr,flag);
        if(flag==1)
        {
            if(pl==m-ql+1) return pl+pr;
            else return pl;
        }
        else
        {
            if(pr==qr-m) return pl+pr;
            else return pr;
        }
    }
}
int a[maxn];
int main()
{
    int n,q;
    while(scanf("%d%d",&n,&q)!=EOF)
    {
        memset(a,0,sizeof a);
        build(1,1,n);
        int tp=0;
        while(q--)
        {
            char s;
            cin>>s;
            if(s==‘D‘)
            {
                int x;
                scanf("%d",&x);
                update(1,1,n,x,0);
                a[++tp]=x;
            }
            if(s==‘Q‘)
            {
                int x;
                scanf("%d",&x);
                int x1=query(1,1,n,1,x,2);
                int x2=query(1,1,n,x,n,1);
                printf("%d\n",x1+x2>0?x1+x2-1:0);
            }
            if(s==‘R‘)
            {
                if(tp>=1)
                {
                    int x=a[tp--];
                    update(1,1,n,x,1);
                }
            }
        }
    }
}

原文地址:https://www.cnblogs.com/iamamori/p/9982915.html

时间: 2024-10-08 22:18:24

HDU 1540(线段树+区间合并)学习记录的相关文章

HDU 4339 线段树区间合并

Query Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2573    Accepted Submission(s): 851 Problem Description You are given two strings s1[0..l1], s2[0..l2] and Q - number of queries.Your task

hdu 3308(线段树区间合并)

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6069    Accepted Submission(s): 2635 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

HDU 3911 线段树区间合并

北京赛区快了,准备袭击数据结构和图论.倒计时 18天,线段树区间合并.维护一个最长连续.. 题意:给一个01串,以下有一些操作,问区间最长的连续的1的个数 思路:非常裸的线段树区间合并 #include<iostream> #include<cstdio> #include<map> #include<set> #include<cmath> #define lson id << 1 #define rson id <<

HDU - 1540 线段树的合并

这个题题意我大概解释一下,就是一开始一条直线,上面的点全是联通的,有三种操作 1.操作D把从左往右第x个村庄摧毁,然后断开两边的联通. 2.询问Q节点相联通的最长长度 3.把最后破坏的村庄重建. 这个其实也是非常典型的线段树区间合并,正好可以学一下. 我们给线段树的结点赋予5个值,l 区间左端点, r 区间右端点, ls从左端点开始的最大连续个数(左连续),rs从右端点开始最大的连续个数,ms这个节点所表示的区间内部,最大的连续个数. 然后我们考虑建树,由于最开始是相通的,因此这些值初始为r-l

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

LCIS Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 6592    Accepted Submission(s): 2866 Problem Description Given n integers.You have two operations:U A B: replace the Ath number by B. (index

hdu 1806(线段树区间合并)

Frequent values Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1476    Accepted Submission(s): 541 Problem Description You are given a sequence of n integers a1 , a2 , ... , an in non-decreasin

HDU 1540 Tunnel Warfare(区间合并)【线段树】

<题目链接> 题目大意: 题意:一个长度为n的线段,下面m个操作 D x 表示将单元x毁掉 R  表示修复最后毁坏的那个单元 Q x  询问这个单元以及它周围有多少个连续的单元,如果它本身已经被毁坏了就是0. 解题分析: 用线段树求指定点所在的最长连续区间,属于线段树区间合并类型的题,线段树的每个节点需要维护三个值,分别是对应区间的最长连续区间长度,对应区间最长连续区间前缀,对应区间最长连续后缀,然后就是在每次update之后都维护一下这三个值就行.并且注意一下query 时的操作. 1 #i

HDU 3308 LCIS(最长连续上升子序列)(线段树区间合并)

题意:给你n个整数,有两种操作,U A B把第A个数变成B,Q A B查询区间[A,B]的最长连续上升序列. 思路:还是查询和更新操作,而且也是询问区间中满足条件的连续最长区间 ,所以是线段树区间合并类型的题,通法是开三棵线段树,一个记录此区间内的LCIS的最长长度,一个记录从左边第一个数开始的LCIS长度,另一个记录从右边最后一个数结尾的LCIS长度.然后试图找到父亲与儿子关系维护的递推关系式就好 本题中的递推关系是: 1. 左儿子最右边的值 < 右儿子最左边的值 lmx = (左儿子的lmx

HDU 3308 LCIS (线段树区间合并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308 题目很好懂,就是单点更新,然后求区间的最长上升子序列. 线段树区间合并问题,注意合并的条件是a[mid + 1] > a[mid],写的细心点就好了. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int MAXN = 1

HDU 5316 Magician(线段树区间合并入门)

本文纯属原创,转载请注明出处谢谢.http://blog.csdn.net/zip_fan. 题目传送门:http://acm.hdu.edu.cn/showproblem.php?pid=5316 Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Problem Description Fantasy magicians usually gain their ability