1. 程式人生 > >hdu-1540線段樹刷題

hdu-1540線段樹刷題


title: hdu-1540線段樹刷題
date: 2018-10-18 19:55:21
tags:

  • acm
  • 刷題
    categories:
  • ACM-線段樹

概述

哇,,,這道線段樹的題可以說是到目前為止我所做過的最難的一道了吧QAQ,,,,,,

一開始讀完題就是一臉懵逼,,,,完全不知道該從哪裡下手,,,就是知道這是一道線段樹的題也不知道該怎麼下手啊啊啊,,,,

最後還是看了kaungbin大佬的程式碼,,,QAQ

光是讀程式碼就花了一兩個小時,,,(不過也有可能和今天賊困有關,,,腦袋不怎麼轉啊

分析思路

題意

大概的題意就是一串在一條線上的村莊,,或者說是點,,,一開始都為1,,,然後有三種不同的操作,,,

  • d a: 意味著將a這個點置為0,,,
  • q a: 意味著詢問a周圍有多少的1,,,只要碰到零就不算了,,,例如110111110,,(q 5) = 5
  • r: 意味著將上一個被置為零的點置為1

分析

我的想法

一開始我看到有需要上一次操作的情況,,就想著要將這些d操作儲存下來,,適合這道題的就是棧,,,

然後就是詢問了,,,我那時想著既然要求a周圍這些1的個數,,那我就找到兩端的0不就行了,,,然後從這裡就徹底的腦抽了,,,又想著用線段樹去求這段區間的和,,,,然後結果顯而易見,,,,t了,,,

因為,,這種想法線段樹根本沒有用啊!!!!都找出那兩端的0所在的位置直接減不就行了,,,這不就是裸暴力嗎,,,,,哇,,,被自己蠢哭(๐॔˃̶ᗜ˂̶๐॓),,,,

斌神的做法

首先將這段線劃分成多個區段,,,每個區段儲存的資訊有:從這去區段的左端點開始最長的連續1的個數ll從這個區段右端點開始的最長的連續1的個數rl 、 還有這個區段最大的連續點的個數ml。。。

建樹:ll = rl = ml = 區間長

更新

葉子節點置一置零,,,

左右遞迴更新

其他區間:(pushup())
父節點.ll = 左節點.ll 父節點.rl = 右節點.rl
父節點.ml取左右節點的最大的一個ml
若左節點的rl + 右節點的ll > 父節點的ml,,,,就更新為前者

對於父節點的ll,rl
如果左節點的ll為左節點的長度,,,就說明左節點從左端點開始的連續1的最大的個數就為左節點包含的點的個數,,,所以此時的父節點的ll就要和右節點的ll合併


同理,,,父節點的rl也要進行這樣的判斷

查詢

對於一些特殊的區間直接返回該區間的最大的連續1的個數也就是ml

當loc在中點左時,,,就要從左節點來判斷,,,判斷的條件是loc是否超出了rl的最左端(畫圖更容易理解一些),,,超出的話就說明loc所在的連續的1一部分是在左節點的rl裡另一部分是在右節點的ll裡,,,就分成兩個點查詢,,,一個是在左節點的loc,,,另一個時在右節點的mid+1那個點
同理,,若在中點的右時也有類似的判斷,,,
大體上說就是不斷地判斷要找到那個點相對ll,rl的位置,,,最後把遞迴查詢到的結果合併就行了,,,

字醜見諒,,,,(不過應該沒人看把,,,,

程式碼

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>

using namespace std;

const int maxn = 5e5 + 10;

struct node
{
    int l;
    int r;
    int ml;
    int ll;
    int rl;
}node[maxn << 2];

void build(int rt , int l , int r)
{
    node[rt].l = l;
    node[rt].r = r;
    node[rt].ml = node[rt].ll = node[rt].rl = r - l + 1;    //剛開始肯定是區間的長度
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(rt << 1 , l , mid);
    build(rt << 1 | 1 , mid + 1 , r);
    return;
}
void update(int rt , int loc , int val)
{
    if(node[rt].l == node[rt].r)
    {
        if(val) node[rt].ml = node[rt].ll = node[rt].rl = 1;    //摧毀和重建兩種
        else    node[rt].ml = node[rt].ll = node[rt].rl = 0;
        return;
    }
    int mid = (node[rt].l + node[rt].r) >> 1;
    if(loc <= mid)  update(rt << 1 , loc , val);
    else            update(rt << 1 | 1 , loc , val);
    //遞迴更新
    //先更新父節點的兩個,ll,rl
    node[rt].ll = node[rt << 1].ll;
    node[rt].rl = node[rt << 1 | 1].rl;

    //然後是父節點的ml
    node[rt].ml = max(node[rt << 1].ml , node[rt << 1 | 1].ml);
    node[rt].ml = max(node[rt].ml , node[rt << 1].rl + node[rt << 1 | 1].ll);

    //父節點的ll,rl可能就是左右節點的ll,,rl,,,,當剛好是子節點的全部時還要加上另一個區間的一部分
    if(node[rt << 1].ll == node[rt << 1].r - node[rt << 1].l + 1)
        node[rt].ll += node[rt << 1 | 1].ll;
    if(node[rt << 1 | 1].rl == node[rt << 1 | 1].r - node[rt << 1 | 1].l + 1)
        node[rt].rl += node[rt << 1].rl;
    return;
}
int query(int rt , int loc)
{
    //特殊情況直接返回ml
    if(node[rt].l == node[rt].r || node[rt].ml == 0 || node[rt].ml == node[rt].r - node[rt].l + 1)
        return node[rt].ml;

    int mid = (node[rt].l + node[rt].r) >> 1;
    if(loc <= mid)
    {
        if(loc >= node[rt << 1].r - node[rt << 1].rl + 1)
            return query(rt << 1 , loc) + query(rt << 1 | 1 , mid + 1);
        else
            return query(rt << 1 , loc);
    }
    else
    {
        if(loc <= node[rt << 1 | 1].l + node[rt << 1 | 1].ll - 1)
            return query(rt << 1 | 1 , loc) + query(rt << 1 , mid);
        return query(rt << 1 | 1 , loc);
    }
}
int main()
{
    int n , m;
    while(scanf("%d%d" , &n , &m) != EOF)
    {
        build(1 , 1 , n);
        int q[maxn];
        int toc = 0;
        int t = 0;
        while(m--)
        {
            char c;scanf(" %c" , &c);
            if(c == 'D')
            {
                scanf("%d" , &t);
                q[toc++] = t;   //把摧毀操作儲存
                update(1 , t , 0);
            }
            else if(c == 'Q')
            {
                scanf("%d" , &t);
                printf("%d\n" , query(1 , t));
            }
            else
            {
                if(t)
                {
                    t = q[--toc];
                    update(1 , t , 1);
                }
            }
        }
    }
    return 0;
}
//kaungbin