hdu1540(线段树)

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

题意:是一条线上的点,D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点。

线段树功能:单点修改,区间求值。

分析: pre数组记录区间左端点开始的最大连续个数,  suf数组记录区间右端点开始往左的最大的连续个数,sum数组表示该区间最大的连续点的个数。

sum[rt]最大值是左区间的最大值或右区间的最大值或左区间的suf+右区间的pre。

#pragma comment(linker,"/STACK:102400000,102400000")
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstdlib>
#include <stack>
#include <vector>
#include <set>
#include <map>
#define LL long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define N 50010
#define FILL(a,b) (memset(a,b,sizeof(a)))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;

int sum[N<<2],pre[N<<2],suf[N<<2];
int a[N];
void Pushup(int rt,int len)
{

    pre[rt]=pre[rt<<1];
    suf[rt]=suf[rt<<1|1];
    if(pre[rt<<1]==(len-(len>>1)))pre[rt]=pre[rt<<1]+pre[rt<<1|1];
    if(suf[rt<<1|1]==(len>>1))suf[rt]=suf[rt<<1]+suf[rt<<1|1];
    sum[rt]=max(suf[1<<1]+pre[1<<1|1],max(sum[rt<<1],sum[rt<<1|1]));
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=pre[rt]=suf[rt]=1;
        return;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
    Pushup(rt,r-l+1);
}
void update(int pos,int c,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=suf[rt]=pre[rt]=c;
        return;
    }
    int m=(l+r)>>1;
    if(pos<=m)update(pos,c,lson);
    else update(pos,c,rson);
    Pushup(rt,r-l+1);
}
int query(int pos,int l,int r,int rt)
{
    if(l==r)
        return sum[rt];
    int m=(l+r)>>1;
    if(pos<=m)
    {
        if(pos+suf[rt<<1]>m)return suf[rt<<1]+pre[rt<<1|1];
        else return query(pos,lson);
    }
    else
    {
        if(m+pre[rt<<1|1]>=pos)return pre[rt<<1|1]+suf[rt<<1];
        else return query(pos,rson);
    }
}
int main()
{
    int n,m,x,tot;
    char op[10];
    while(scanf("%d%d",&n,&m)>0)
    {
        build(1,n,1);
        tot=0;
        while(m--)
        {
            scanf("%s",op);
            if(op[0]==‘Q‘)
            {
                scanf("%d",&x);
                printf("%d\n",query(x,1,n,1));
            }
            else if(op[0]==‘D‘)
            {
                scanf("%d",&x);
                a[++tot]=x;
                update(x,0,1,n,1);
            }
            else
            {
                x=a[tot--];
                update(x,1,1,n,1);
            }
        }
    }
}

时间: 2024-08-25 12:16:15

hdu1540(线段树)的相关文章

hdu1540 线段树区间合并

先说下题意: 有连续的n个村庄编号1--n    开始相邻的能连续上  现在执行m次操作 1:毁坏村庄a 2:询问与a能连续的村庄的个数 3:修好最后被毁坏的村庄(此处用到栈 注意多次毁坏同一村庄的情况) 整天还是线段树做  对每个节点存3个值 pre :左端点连续个数 after :右端点连续个数 Max:整个区间连续个数 跟新操作分为毁坏和维修  用-1和1区别 这道题与别的不同在于他的点询问        可以根据Max来判断 #include<stdio.h> #include<

HDU1540(线段树统计连续长度)

---恢复内容开始--- Tunnel Warfare Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Description During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Genera

hdu1540 Tunnel Warfare 线段树/树状数组

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly con

kuangbin专题七 HDU1540 Tunnel Warfare (前缀后缀线段树)

During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly con

线段树题目总结

一.单点更新 1.hdu1166 敌兵布阵:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)"Addij",表示第i个营地增加j人.(2)"Sub i j",表示第i个营地减少j人.(3)"Query ij",查询第i个营地到第j个营地的总人数.(4)"End",表示命令结束.解题报告Here. 2.hdu1754 I Hate It:给你N个数,M个操作,操作分两类.(1)"QAB"

数据结构---线段树

线段树 转载请注明出处,谢谢!http://blog.csdn.net/metalseed/article/details/8039326  持续更新中···   一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树

(转载)线段树模板(来自胡浩大牛)

http://www.notonlysuccess.com/(今天看二叉树,想回来看看,发现大牛博客进不去...) 如果要学,就要好好学.我copy的,如有错,请看http://www.cnblogs.com/Mu-Tou/archive/2011/08/11/2134427.html [完全版]线段树 很早前写的那篇线段树专辑至今一直是本博客阅读点击量最大的一片文章,当时觉得挺自豪的,还去pku打广告,但是现在我自己都不太好意思去看那篇文章了,觉得当时的代码风格实在是太丑了,很多线段树的初学者

线段树总结 (转载 里面有扫描线类 还有NotOnlySuccess线段树大神的地址)

转载自:http://blog.csdn.net/shiqi_614/article/details/8228102 之前做了些线段树相关的题目,开学一段时间后,想着把它整理下,完成了大牛NotOnlySuccess的博文“完全版线段树”里的大部分题目,其博文地址Here,然后也加入了自己做过的一些题目.整理时,更新了之前的代码风格,不过旧的代码仍然保留着. 同样分成四类,不好归到前四类的都分到了其他.树状数组能做,线段树都能做(如果是内存限制例外),所以也有些树状数组的题目,会标示出来,并且放

线段树——转

  一:线段树基本概念 1:概述 线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)! 性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍 2:基本操作(demo用的是查询区间最小值) 线段树的主要操作有: (1):线段树的构造 void build(int node,