hdu 1540(线段树区间合并)

题目链接:传送门

参考文章:传送门

题意:n个数字初始连在一条线上,有三种操作,

D x表示x号被摧毁;

R 表示恢复剩下的通路

Q表示查询标号为x所在的串的最长长度。

思路:线段树的区间合并。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 50500;
struct Node{
    int l,r;
    int ls,rs,ms;
}cur[maxn<<2];
int ss[maxn],m,n;
void build(int x,int l,int r) //初始化建树
{
    cur[x].l=l;cur[x].r=r;
    cur[x].ls=cur[x].rs=cur[x].ms=r-l+1;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
}
int MAX(int x,int y)
{
    return x>y?x:y;
}
void update(int x,int pos,int fg)
{
    if(cur[x].l==cur[x].r)
    {
        if(fg==0) cur[x].ls=cur[x].rs=cur[x].ms=0; //删除
        else cur[x].ls=cur[x].rs=cur[x].ms=1; //更新
        return ;
    }
    int mid=(cur[x].l+cur[x].r)>>1;
    if(pos<=mid) update(x*2,pos,fg);
    else update(x*2+1,pos,fg);
    //pushup操作,更新左子区间,右子区间的最长长度
    cur[x].ls=cur[x*2].ls;
    cur[x].rs=cur[x*2+1].rs;
    cur[x].ms=MAX(MAX(cur[x*2].ms,cur[x*2+1].ms),cur[x*2].rs+cur[x*2+1].ls);
    if(cur[x*2].ls==cur[x*2].r-cur[x*2].l+1) cur[x].ls+=cur[x*2+1].ls; //如果区间的左子树的左区间已经满了,就加上右子树的左子区间
    if(cur[x*2+1].rs==cur[x*2+1].r-cur[x*2+1].l+1) cur[x].rs+=cur[x*2].rs; // 如果右子树的右子区间已经满了,就加上左子树的右子区间
}
int query(int x,int pos)
{
    if(cur[x].ms==0||cur[x].l==cur[x].r||cur[x].ms==cur[x].r-cur[x].l+1) return cur[x].ms;
    int mid=(cur[x].l+cur[x].r)>>1;
    if(pos<=mid)
    {
        if(pos>=cur[x*2].r-cur[x*2].rs+1) return query(x*2,pos)+query(x*2+1,mid+1);//如果在左子区间的右边界,就遍历两个区间
        return query(x*2,pos);
    }
    else
    {
        if(pos<=cur[x*2+1].l+cur[x*2+1].ls-1) return query(x*2+1,pos)+query(x*2,mid); //如果在右子区间的左边界,就遍历两个区间
        return query(x*2+1,pos);
    }
}
int main(void)
{
    while(~scanf("%d%d",&n,&m))
    {
        build(1,1,n);
        char op[2];
        int x,top=0;
        while(m--)
        {
            scanf("%s",op);
            if(op[0]==‘D‘)
            {
                scanf("%d",&x);
                ss[top++]=x;
                update(1,x,0);
            }
            else if(op[0]==‘Q‘)
            {
                scanf("%d",&x);
                printf("%d\n",query(1,x));
            }
            else if(op[0]==‘R‘)
            {
                x=ss[--top];
                update(1,x,1);
            }
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/2018zxy/p/10201702.html

时间: 2024-10-11 00:05:41

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 (线段树区间合并)

题目链接: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

HDU 3911 Black And White(线段树区间合并)

Problem Description There are a bunch of stones on the beach; Stone color is white or black. Little Sheep has a magic brush, she can change the color of a continuous stone, black to white, white to black. Little Sheep like black very much, so she wan