zoukankan      html  css  js  c++  java
  • HDU1540 Tunnel Warfare 线段树

    http://acm.hdu.edu.cn/showproblem.php?pid=1540

    题义是对于一段线段,D x 表示破坏x点,R 表示回复最近一次被破坏的点,Q x表示询问以x点为中心的两头的最长的连续区间。改了2个小时,终于A掉了,吐血啊,尤其是杭电的测试数据,一个点可以破坏多次,这小日本鬼子也忒坏吧,再说了如果一个点破坏多次,八路军叔叔也要修理多次吗,题义与实际既不符合,还是POJ厚道。

    该题分两部来做,首先是建立一棵线段树,这颗线段树应该保留有一下信息:

    1. 该区间的左连续长度,右连续长度
    2. 该区间的覆盖情况(即是否没有发生任何破坏)这是线段树以空间换时间的地方

    然后就是求连续的区间长度了,我得出结果的步骤是这样的:

    A. 首先判定这个节点(x)是否已经被摧毁,如果摧毁直接返回0
    B. 如果没有被摧毁的话,就求1 ~ x-1 的右连续段以及 x+1 ~ N 的左连续段再加上自己本身的1

    对于R操作的话,用意个stack就行了,注意杭电的一个点可以被多次破坏。

    代码如下:

    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <stack>
    #define MAXN 50005
    using namespace std;

    struct Node
    {
    int l, r;
    int lenl, lenr, cover;
    }seg[MAXN*3];

    char rec[MAXN];

    void creat(int f, int l, int r)
    {
    int mid = (l+r)>>1;
    seg[f].l = l, seg[f].r = r;
    seg[f].lenl = r-l;
    seg[f].lenr = r-l;
    seg[f].cover = 1;
    if (r - l > 1)
    {
    creat(f<<1, l, mid);
    creat(f<<1|1, mid, r);
    }
    }

    void modify(int f, int l, int r, int val)
    {
    int mid = (seg[f].l + seg[f].r)>>1;
    if (seg[f].l == l && r == seg[f].r)
    {
    seg[f].lenl = seg[f].lenr = val;
    seg[f].cover = val;
    }
    else if (seg[f].r - seg[f].l > 1)
    {
    if (seg[f].cover == 1)
    { // lazy 操作
    seg[f<<1].cover = seg[f].cover;
    seg[f<<1|1].cover = seg[f].cover;
    seg[f].cover = 0;
    }
    if (r <= mid)
    modify(f<<1, l, r, val);
    else if (l >= mid)
    modify(f<<1|1, l, r, val);
    else
    {
    modify(f<<1, l, mid, val);
    modify(f<<1|1, mid, r, val);
    }
    seg[f].lenl = seg[f<<1].lenl;
    seg[f].lenr = seg[f<<1|1].lenr;
    if (seg[f<<1].cover == 1)
    seg[f].lenl += seg[f<<1|1].lenl;
    if (seg[f<<1|1].cover == 1)
    seg[f].lenr += seg[f<<1].lenr;
    // 更新左右区间的连续长度
    seg[f].cover = seg[f<<1].cover && seg[f<<1|1].cover;
    // 回溯cover的值
    }
    }

    int lquery(int f, int l, int r)
    {
    int mid = (seg[f].l+seg[f].r)>>1;
    if (seg[f].l == l && r == seg[f].r)
    {
    return seg[f].lenl;
    }
    else if (seg[f].r - seg[f].l > 1)
    {
    if (r <= mid)
    return lquery(f<<1, l, r);
    else if (l >= mid)
    return lquery(f<<1|1, l, r);
    else
    {
    int c = lquery(f<<1, l, mid);
    if (c == mid-l)
    {
    c += lquery(f<<1|1, mid, r);
    }
    return c;
    }
    }
    else return 0;
    }


    int rquery(int f, int l, int r)
    {
    int mid = (seg[f].l+seg[f].r)>>1;
    if (seg[f].l == l && r == seg[f].r)
    {
    return seg[f].lenr;
    }
    else if (seg[f].r - seg[f].l > 1)
    {
    if (r <= mid)
    return rquery(f<<1, l, r);
    else if (l >= mid)
    return rquery(f<<1|1, l, r);
    else
    {
    int c = rquery(f<<1|1, mid, r);
    if (c == r-mid)
    {
    c += rquery(f<<1, l, mid);
    }
    return c;
    }
    }
    else
    return 0;
    }

    int main()
    {
    int N, M, x;
    char op[10];
    while (scanf("%d %d", &N, &M) == 2)
    {
    stack<int>stk;
    memset(rec, 1, sizeof (rec));
    creat(1, 1, N+1);
    for (int i = 0; i < M; ++i)
    {
    scanf("%s", op);
    if (op[0] == 'R')
    {
    if (!stk.empty())
    {
    int c = stk.top();
    rec[c] = 1;
    stk.pop();
    modify(1, c, c+1, 1);
    }
    }
    else if (op[0] == 'D')
    {
    scanf("%d", &x);
    rec[x] = 0;
    stk.push(x);
    modify(1, x, x+1, 0);
    }
    else
    {
    scanf("%d", &x);
    if (rec[x] == 0)
    printf("0\n");
    else
    printf("%d\n", lquery(1, x+1, N+1)+rquery(1, 1, x)+1);
    }
    }
    }
    return 0;
    }



  • 相关阅读:
    oracle 查找或删除重复记录的语句
    多线程案例
    JAVA调用增删改的存储过程
    设计中最常用的CSS选择器
    ORACLE多表查询优化
    oracle存储过程的事务处理
    oracle函数调用存储过程
    oracle存储过程的基本语法
    java.lang.OutOfMemoryError: Java heap space解决方法
    文件操作工具类
  • 原文地址:https://www.cnblogs.com/Lyush/p/2371052.html
Copyright © 2011-2022 走看看