Tunnel Warfare HDU - 1540(线段树最长连续区间)

题意:

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

解析:

线段树结点 设置一个  lq记录区间左端点开始的最大连续个数,  rq 记录区间右端点开始的最大的连续个数

其它和原来一样即可

看代码吧。。。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <stack>
#include <queue>
#include <algorithm>
#include <cmath>
#define mem(a, b) memset(a, b, sizeof(a))
using namespace std;
const int maxn = 1000010, INF = 0x7fffffff;
typedef long long LL;
int a, b, x, y, ans;

struct node{
    int l, r, w, lq, rq;
}Node[maxn];

void build(int k, int ll, int rr)
{
    Node[k].l = ll, Node[k].r = rr;
    if(Node[k].l == Node[k].r)
    {
        Node[k].lq = Node[k].rq = Node[k].w = 1;
        return;
    }
    int m = (ll + rr) / 2;
    build(k*2, ll, m);
    build(k*2+1, m+1, rr);
    Node[k].lq = Node[k].rq = Node[k].w = Node[k*2].w + Node[k*2+1].w;
}

void chp(int k)  //单点修改
{
    if(Node[k].l == Node[k].r)
    {
        Node[k].lq = Node[k].rq = Node[k].w = y;
        return;
    }
    int m = (Node[k].l + Node[k].r) / 2;
    if(x <= m) chp(k*2);
    else chp(k*2+1);
    Node[k].w = Node[k*2].w + Node[k*2+1].w;
    Node[k].lq = Node[k*2].lq;           //修改后初始化 父结点的最长连续左区间 为 左子结点的最长连续左区间
    Node[k].rq = Node[k*2+1].rq;         //父结点的最长连续右区间 为 右子结点的最长连续右区间
    if(Node[k*2].lq == Node[k*2].r - Node[k*2].l + 1)  //如果左子结点的最长连续左区间 为整个区间的长度 那么父结点的最长连续左区间 应该 加上 右子结点的最长连续右区间
        Node[k].lq += Node[k*2+1].lq;
    if(Node[k*2+1].rq == Node[k*2+1].r - Node[k*2+1].l + 1) // 同理
        Node[k].rq += Node[k*2].rq;
}

void qinter(int k, int t)
{
    if(Node[k].l == Node[k].r || Node[k].w == 0 || Node[k].w == Node[k].r - Node[k].l + 1) //如果当前区间为单点、区间和为0、区间和为区间长度 那么就没必要往下搜了 返回即可
    {
        ans += Node[k].w;
        return;
    }
    int m = (Node[k].l + Node[k].r) / 2;
    if(t <= m)   //如果t在左子树
    {
        if(t >= Node[k*2].r - Node[k*2].rq + 1)  //如果t大于左子树右区间的左端点 说明t在左子树的右区间内
        {
            ans += (Node[k*2].rq + Node[k*2+1].lq);  //然后用左子树的最长连右区间 + 右子树的最长连续左区间
            return;
        }
        else
            qinter(k*2, t);  //如果不在右区间 则向下搜
    }
    else //同理
    {
        if(t <= Node[k*2+1].l + Node[k*2+1].lq - 1)
        {
            ans += (Node[k*2+1].lq + Node[k*2].rq);
            return;
        }
        else
            qinter(k*2+1, t);
    }
}

int main()
{
    int n, m;
    ans = 0;
   while(~scanf("%d%d",&n,&m)){
        build(1, 1, n);
        stack<int> G;
        getchar();
        for(int i=0; i<m; i++)
        {
            char str[1010];
            scanf("%s",str);
            if(strcmp(str, "D") == 0)
            {
                scanf("%d",&x);
                G.push(x);
                y = 0;
                chp(1);
            }
            else if(strcmp(str, "R") == 0)
            {
                x = G.top();
                G.pop();
                y = 1;
                chp(1);
            }
            else if(strcmp(str, "Q") == 0)
            {
                scanf("%d",&x);
                ans = 0;
                qinter(1, x);
                printf("%d\n",ans);
            }

        }
   }
    return 0;
}

原文地址:https://www.cnblogs.com/WTSRUVF/p/9244787.html

时间: 2024-10-12 09:47:08

Tunnel Warfare HDU - 1540(线段树最长连续区间)的相关文章

I - Tunnel Warfare HDU - 1540 线段树最大连续区间

题意  :一段区间  操作1 切断点 操作2 恢复最近切断的一个点 操作3 单点查询该点所在最大连续区间 思路:  主要是push_up :  设区间x 为母区间  x<<1 ,x<<1|1分别为两个子区间 x的左端连续子段和 :当x<<1区间没有断开 也就是 x<<1 的最大连续子段ml ==tree[x<<1].r-tree[x<<1].l+1 等于区间长度时 x左端连续字段和tree[x].ll=tree[x<<1]

Tunnel Warfare HDU 1540 区间合并+最大最小值

Tunnel Warfare HDU 1540 区间合并+最大最小值 题意 D x是破坏这个点,Q x是表示查询以x所在的最长的连续的点的个数,R是恢复上一次破坏的点. 题解思路 参考的大佬博客 这里巧妙使用了最大值最小值来进行区间的查找.上一行是大佬的详细题解,真的很妙啊. 代码实现 #include<cstdio> #include<cstring> #include<algorithm> #include<stack> #define ls (rt&l

HDU - 1540 线段树的合并

这个题题意我大概解释一下,就是一开始一条直线,上面的点全是联通的,有三种操作 1.操作D把从左往右第x个村庄摧毁,然后断开两边的联通. 2.询问Q节点相联通的最长长度 3.把最后破坏的村庄重建. 这个其实也是非常典型的线段树区间合并,正好可以学一下. 我们给线段树的结点赋予5个值,l 区间左端点, r 区间右端点, ls从左端点开始的最大连续个数(左连续),rs从右端点开始最大的连续个数,ms这个节点所表示的区间内部,最大的连续个数. 然后我们考虑建树,由于最开始是相通的,因此这些值初始为r-l

Tunnel Warfare HDU - 1540

学习set,其他容器每次都要去sort(),除了堆(但其无法lower_bound) 题面 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 t

I - Tunnel Warfare - hdu 1540

#include <iostream>//未完成 #include <cstdio> using namespace std; const int maxn=50005; #define lson rt<<1 #define rson rt<<1|1 struct st { int l,r,len; int mid() { return (l+r)>>1; } }a[maxn<<2]; void bst(int rt,int l,in

I - Tunnel Warfare - hdu 1540(区间合并更新)

题意:在抗日战争期间,地道战在华北平原得到广泛的实施,一般而言,村庄通过一些隧道在一条线上连接,除了两端剩下的每个村庄都有两个相连. 侵略者会频繁的对这些村庄进行扫荡,并且摧他们的地道,当然八路军会把这一些已经被摧毁的村庄修复的,会优先修复最近被破坏的村庄. 分析:被这道题折磨了一上午啊,不过也学到了很多,尤其是这种涉及左右区间的. ********************************************************************* #include<std

hdu 2795 线段树(二维问题一维化)

Billboard Time Limit: 20000/8000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10961    Accepted Submission(s): 4863 Problem Description At the entrance to the university, there is a huge rectangular billboard of s

hdu 3308 线段树单点更新 区间合并

http://acm.hdu.edu.cn/showproblem.php?pid=3308 学到两点: 1.以区间端点为开始/结束的最长......似乎在Dp也常用这种思想 2.分类的时候,明确标准逐层分类,思维格式: 条件一成立: { 条件二成立: { } else { } } else { 条件二成立: { } else { } } 上面的这种方式很清晰,如果直接想到那种情况iif(条件一 &条件二)就写,很容易出错而且把自己搞乱,或者情况不全,,,我就因为这WA了几次 3.WA了之后 ,

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