HDU 1540 POJ 2892 线段树区间合并

给出N个点,M次操作,N个点开始在一条线上链式相连

D操作  把某点删除掉

Q操作  询问某点一共可以连接多少个点

R操作  把上一次删除的点还原

线段树处理区间合并

分别记录每个区间的左端连续最长和右端连续最长

#include "stdio.h"
#include "string.h"

struct node
{
    int l,r,lx,rx,x;
}data[200010];
int mark[50100];
int Max(int a,int b)
{
    if (a<b) return b;else return a;
}
void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    data[k].lx=data[k].rx=data[k].x=data[k].r-data[k].l+1;

    if (l==r) return ;

    mid=(l+r)/2;

    build(l,mid,k*2);
    build(mid+1,r,k*2+1);
}

void updata(int x,int k,int op)
{
    int mid,ll,rr;
    if (data[k].l==data[k].r)
    {
        data[k].lx=data[k].rx=data[k].x=op;
        return ;
    }

    mid=(data[k].l+data[k].r)/2;

    if (x<=mid) updata(x,k*2,op);
    else
        if (x>mid) updata(x,k*2+1,op);

    ll=data[k*2].r-data[k*2].l+1;
    rr=data[k*2+1].r-data[k*2+1].l+1;

    data[k].lx=data[k*2].lx;
    if (data[k*2].lx==ll) data[k].lx+=data[k*2+1].lx;

    data[k].rx=data[k*2+1].rx;
    if (data[k*2+1].rx==rr) data[k].rx+=data[k*2].rx;

    data[k].x=Max(Max(data[k*2].x,data[k*2+1].x),data[k*2].rx+data[k*2+1].lx);
}

int query(int x,int k)
{
    int mid;
    if (data[k].l==data[k].r || data[k].x==0 || data[k].x==data[k].r-data[k].l+1)
        return data[k].x;

    mid=(data[k].l+data[k].r)/2;
    if (x<=mid)
    {
        if (data[k*2].r-x+1<=data[k*2].rx)
            return query(x,k*2)+query(mid+1,k*2+1);
        else
            return query(x,k*2);
    }
    else
    {
        if (x-data[k*2+1].l+1<=data[k*2+1].lx)
            return query(x,k*2+1)+query(mid,k*2);
        else
            return query(x,k*2+1);
    }
}

int main()
{
    int cnt,n,m,x;
    char ch[10];
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        build(1,n,1);
        cnt=0;
        while (m--)
        {
            scanf("%s",ch);
            if (ch[0]=='D')
            {
                scanf("%d",&x);
                mark[cnt++]=x;
                updata(x,1,0);
            }
            if (ch[0]=='Q')
            {
                scanf("%d",&x);
                printf("%d\n",query(x,1));
            }
            if (ch[0]=='R')
            {
                cnt--;
                if (cnt<0) cnt=0;
                else updata(mark[cnt],1,1);
            }
        }
    }
    return 0;
}
时间: 2024-10-15 17:12:52

HDU 1540 POJ 2892 线段树区间合并的相关文章

HDU 1540 Tunnel Warfare(线段树 区间合并 最大连续区间)

题意  有n个连在一起的地道  接下来有m个操作  D x 炸掉x号地道  炸掉后x所在的区间就不连续了  Q x 查询输出包括x的最大连续区间长度   R修复最后一个被炸的地道  注意输入R时可能并没有需要修复的地道 线段树的区间合并问题  线段树要维护3个信息 len  对应区间的最大连续长度 ll  对应区间最左端的一段连续长度 lr  对应区间最右端的一段连续长度 那么双亲节点的这些信息和孩子节点有什么关系呢  容易发现 双亲的len 是 左孩子的len 右孩子的len  左孩子的右端长

HDU 1540 Tunnel Warfare 线段树区间合并

Tunnel Warfare 题意:D代表破坏村庄,R代表修复最后被破坏的那个村庄,Q代表询问包括x在内的最大连续区间是多少 思路:一个节点的最大连续区间由(左儿子的最大的连续区间,右儿子的最大连续区间,左儿子的最大连续右区间+右儿子的最大连续左区间)决定 所以线段树的节点应该维护当前节点的最大连续左区间,最大连续右区间,和最大连续区间. 注意更新的时候,如果左儿子全满,父亲节点的左连续区间还要加上右儿子的左区间.反之同理. 查询的时候,可以剪枝,如果是叶子,或为空,或满,则不用往下查询. 查询

hdu 1540 Tunnel Warfare 线段树 区间合并

题意: 三个操作符 D x:摧毁第x个隧道 R x:修复上一个被摧毁的隧道,将摧毁的隧道入栈,修复就出栈 Q x:查询x所在的最长未摧毁隧道的区间长度. 1.如果当前区间全是未摧毁隧道,返回长度 2.如果在坐儿子的右区间或右儿子的左区间,返回这两个区间长度和 3.继续递归 #include <bits/stdc++.h> #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 using namespace std;

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

POJ 3667 线段树区间合并

http://www.cnblogs.com/scau20110726/archive/2013/05/07/3065418.html 用线段树,首先要定义好线段树的节点信息,一般看到一个问题,很难很快能确定线段树要记录的信息做线段树不能为了做题而做,首先线段树是一种辅助结构,它是为问题而生的,因而必须具体问题具体分析回忆一下RMQ问题,其实解决RMQ有很多方法,根本不需要用到线段树,用线段树解决RMQ,其实是利用线段树的性质来辅助解决这个问题回忆一下求矩形面积并或周长并的问题,一般使用的是扫描

hdu 1698+poj 3468 (线段树 区间更新)

http://acm.hdu.edu.cn/showproblem.php?pid=1698 这个题意翻译起来有点猥琐啊,还是和谐一点吧 和涂颜色差不多,区间初始都为1,然后操作都是将x到y改为z,注意 是改为z,不是加或减,最后输出区间总值 也是线段树加lazy操作 1 #include<cstdio> 2 using namespace std; 3 struct point { 4 int l,r; 5 int val,sum; 6 }; 7 point tree[400007]; 8

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

题目传送:LCIS 线段树,区间合并,一次过啦,没有纠结,这几天过的最愉快的一个题 思路:求最长连续上升子序列,外带单点更新,经典的线段树题目.具体看代码注释 AC代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <cmath> #include <queue> #include <stack>

HDU 5316——Magician——————【线段树区间合并区间最值】

Magician Time Limit: 18000/9000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1613    Accepted Submission(s): 470 Problem Description Fantasy magicians usually gain their ability through one of three usual methods:

poj 3667(线段树 区间合并) 开房吧

http://poj.org/problem?id=3667 宾馆有n个房间编号1到n都为空房,然后m个询问,当输入第一个为1的时候,代表要住进x个连续的房间,输入房间号最小的数,如果没有 输出0.当第一个数为2的时候,将从x号到y号的房间又变为空房,没有输出 与区间有关想想用线段树可不可以解决,就像是涂颜色一样把住与未住的房间号做个标记就行,问题是这里给的是区间的长度,并不是 具体的区间,处理起来比较麻烦 还要去找合适的区间,所以引入了len1表示某区间可用的最大长度,len2表示从区间左端开