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. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!

Input

The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.

There are three different events described in different format shown below:

D x: The x-th village was destroyed.

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.

R: The village destroyed last was rebuilt.

Output

Output the answer to each of the Army commanders’ request in order on a separate line.

Sample Input

7 9

D 3

D 6

D 5

Q 4

Q 5

R

Q 4

R

Q 4

Sample Output

1

0

2

4

模板题目,解释代码中

#include"cstdio"
#include"algorithm"
using namespace std;
const int MAXN=50005;
struct node{
    int l,r;
    int ll,rl,ml;
}a[MAXN*3];
void build(int rt,int l,int r)
{
    a[rt].l=l;
    a[rt].r=r;
    a[rt].ll=a[rt].rl=a[rt].ml=r-l+1;
    if(l==r)    return ;
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build((rt<<1)|1,mid+1,r);
}

void merge(int rt)
{
    //若左子树已满,则应与右子树左区间合并
    a[rt].ll=a[rt<<1].ll;
    if(a[rt<<1].ll==(a[rt<<1].r-a[rt<<1].l+1))
    {
        a[rt].ll+=a[(rt<<1)|1].ll;
    }

    //若右子树已满,则应与左子树的有区间合并
    a[rt].rl=a[(rt<<1)|1].rl;
    if(a[(rt<<1)|1].rl==(a[(rt<<1)|1].r-a[(rt<<1)|1].l+1))
    {
        a[rt].rl+=a[rt<<1].rl;
    }
    //该子树的最大连续长度为 左或右子树连续长度的最大者 或者 将左子树右区间与右子树左区间合并的长度
    a[rt].ml=max(max(a[rt<<1].ml,a[(rt<<1)|1].ml),a[rt<<1].rl+a[(rt<<1)|1].ll);
}

void update(int rt,int pos,int val)
{
    if(a[rt].l==a[rt].r)
    {
        if(val)    a[rt].ll=a[rt].rl=a[rt].ml=1;
        else a[rt].ll=a[rt].rl=a[rt].ml=0;
        return ;
    }

    int mid=(a[rt].l+a[rt].r)>>1;

    if(pos<=mid)    update(rt<<1,pos,val);
    else update((rt<<1)|1,pos,val);
    merge(rt);
}

int query(int rt,int pos)
{
    if(a[rt].l==a[rt].r||a[rt].ml==0||a[rt].ml==a[rt].r-a[rt].l+1)//到达叶子节点或者该节点已满或空,那么不必向下走了
    {
        return a[rt].ml;
    }

    int mid=(a[rt].l+a[rt].r)>>1;

    if(pos<=mid)//在左子树中
    {
        if(pos>=a[rt<<1].r-a[rt<<1].rl+1)//若在左子树的右区间
        {
            return query(rt<<1,pos)+query((rt<<1)|1,mid+1);//则需要查询右子树
        }
        else
        {
            return query(rt<<1,pos);
        }

    }
    else
    {
        if(pos<=a[(rt<<1)|1].l+a[(rt<<1)|1].ll-1)//若在右子树的左区间
        {
            return query((rt<<1)|1,pos)+query(rt<<1,mid);//则需要查询左子树
        }
        else
        {
            return query((rt<<1)|1,pos);
        }
    }
}

int stack[MAXN];
int top;

int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        int pos;
        top=0;
        build(1,1,n);
        while(m--)
        {
            scanf("%*c");
            char op;scanf("%c",&op);
            if(op==‘D‘)
            {
                scanf("%d",&pos);
                stack[top++]=pos;
                update(1,pos,0);
            }
            else if(op==‘Q‘)
            {
                scanf("%d",&pos);
                printf("%d\n",query(1,pos));
            }
            else
            {
                pos=stack[--top];
                update(1,pos,1);
            }
        }
    }
}

---恢复内容结束---

时间: 2024-10-29 02:52:01

HDU1540(线段树统计连续长度)的相关文章

ZOJ 2301 / HDU 1199 Color the Ball 离散化+线段树区间连续最大和

题意:给你n个球排成一行,初始都为黑色,现在给一些操作(L,R,color),给[L,R]区间内的求染上颜色color,'w'为白,'b'为黑.问最后最长的白色区间的起点和终点的位置. 解法:先离散化,为了防止离散后错误,不仅将L,R离散,还要加入L+1,L-1,R+1,R-1一起离散,这样就绝不会有问题了.然后建线段树,线段树维护四个值: 1.col  区间颜色  0 表示黑  1 表示白  -1表示无标记 2.maxi 区间内最大白区间的长度,由于白色用1表示,所以最大白区间的长度即为区间最

hdu1540 线段树区间合并

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

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

F - Count the Colors ZOJ 1610 (线段树+结点为长度为一的区间+树的遍历)

F - Count the Colors Time Limit:2000MS Memory Limit:65536KB 64bit IO Format:%lld & %llu Submit Status Practice ZOJ 1610 Description Painting some colored segments on a line, some previously painted segments may be covered by some the subsequent ones.

[题解](线段树最大连续子段和)POJ_3667_Hotel

题意:1.求一个最靠左的长x的区间全部为0,并修改为1,输出这个区间的左端点 2.修改一个区间为0 实际上是维护最大连续子段和,原来也写过 大概需要维护一个左/右最大子段和,当前这段最大子段长,再维护一个lazytag #include<iostream> #include<cstdio> #include<cstring> #define mid (l+r>>1) #define ls x<<1 #define rs x<<1|1

Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)

题目链接 题意:开始有一个空白的区间,每次可能进行两个操作:A 将一个长度为p的区间加入一段连续空白的位置 L:一个区间恢复空白:要求出A不能进行的次数. 非常裸的线段树题目,用线段树统计最大的空白区间,每个节点需要记录当前区间的最长空白区间,从左端开始的最长空白区间,从右端开始的最长空白区间.Push_up的时候要讨论下,可以分别取[l,mid]和[mid+1,r]的最大空白区间,也可以用[l,mid]的从右端开始的最长空白区间+[mid+1,r]从左端开始的最大空白区间. 每次A的时候,就查

线段树详解 (原理,实现与应用)

线段树详解 By 岩之痕 目录: 一:综述 二:原理 三:递归实现 四:非递归原理 五:非递归实现 六:线段树解题模型 七:扫描线 八:可持久化 (主席树) 九:练习题 一:综述 假设有编号从1到n的n个点,每个点都存了一些信息,用[L,R]表示下标从L到R的这些点. 线段树的用处就是,对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是O(log2(n)). 线段树的原理,就是,将[1,n]分解成若干特定的子区间(数量不超过4*n),然后,将每个区间[L,R]都分解为 少量特定的子区

奇偶线段树(区间更新)

题目链接:http://ccnu.acmclub.com/index.php?app=problem_title&id=613&problem_id=23875 题意:给你一个长度为n的数组(下标从1开始).进行如下操作. (1)1 x y v :表示将下标=(x,x+2,x+4,x+6,.......并且<=y)的元素全部+v: (2)2 x y :查询[x,y]闭区间的元素和. 思路:构造2棵线段树.将区间[1,3,...,2k - 1]改为[1,2,...,k],用一棵线段树统

算法导论学习-线段树(2)

线段树(1)http://www.cnblogs.com/fu11211129/p/4230000.html 1. 线段树应用之动态点插与统计: -------------------------------- 线段树(1)中讲的应用是区段的插值与统计,我们在线段树结构体中接入cover之一域,cover等于0表示该节点所代表的区域并没有被完全覆盖,cover大于等于1表示该节点所代表区域已经被完全覆盖,用线段树(1)博客里面的图来说明一下:           如上图所示,我们最后统计的时候是