HDU 1540 線段樹(區間查詢)

2021-08-04 23:39:03 字數 1688 閱讀 5858

有n個點,每兩個點之間存在一條通路,d x代表摧毀x點,r代表修復最近摧毀的乙個點。q x代表查詢x點能連線多少個村莊(包括自己)。

比較複雜的線段樹。狀態需要用結構體儲存。

l,r代表左邊界和右邊界,ls代表左連續區間長度,rs代表右連續區間長度。ms代表區間內最大連續長度。

初始化過程都初始化成1就可以了。

更新過程就比較複雜了,對於摧毀的點,更新成0就可以了。向上更新的過程需要做一些處理。

首先要判斷左子區間的左連續區間長度==左子區間長度,如果相等的話,則代表左子區間連續,則當前區間的ls為左子區間的ls+右子區間的ls。否則當前區間的ls為左子區間的ls。

然後要判斷右子區間的右連續區間長度==右子區間長度,如果相等的話,則代表右子區間連續,則當前區間的rs為右子區間的rs+左子區間的rs。否則當前區間的rs為右子區間的rs。

ms為左子區間ms,右子區間ms,左子區間rs+右子區間ls三者中的最大值。

查詢的過程也需要做一定的處理。首先判斷ms是否等於區間長度或者等於0。這兩種情況代表區間內無連續區間和區間內為全連續,因此就不用再向下進行判斷。l==r的時候也需要進行判斷,這種情況連續長度就只可能為0或1。

如果不滿足上述條件,就需要根據查詢點的特徵來進行查詢了。如果查詢點在左子區間,就在左子區間進行查詢,這裡要注意判斷點在左子區間的右連續區間這一種特殊情況,在這種特殊情況下,連續區間的長度為左子區間rs+右子區間ls。對於右子區間的查詢也同理,需要特殊判斷在右子區間的ls中這一種情況。

題目中需要考慮的特殊情況很多,稍有不慎就會wa。尤其是查詢時的對查詢點是否在邊界區間的特殊判斷一定要注意。

#include 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define up(i,l,h) for(int i=l;i#define down(i,h,l) for(int i=h-1;i>=l;i--)

#define w(a) while(a)

#define mem(a,b) memset(a,b,sizeof(a))

#define inf 0x3f3f3f3f

#define ll long long

#define maxn 400010

#define eps 1e-10

#define mod 100000000

using

namespace

std;

struct node ;

node nodes[220000];

int p,lt,rt;

void build(int o,int l,int r) else

}void update(int o,int l,int r,bool des) else

} else

}int query(int o,int l,int r) else else

} else else }}

}int main() else

if(c=='q') else

if(c=='r') }}

}

線段樹 區間合併 HDU 1540

題意 題意 d 破壞村莊,r 修復最後乙個破損的村莊,q 查詢x在內的連續區間值有多少 思路 建立線段樹,維護左右區間值。注意維護變數為 從左編開始最大連續值,從右邊開始最大值,最大連續值 為了維護最後乙個被破壞的。需要時刻記錄,並且不能只單純記錄乙個,而是需要記錄順序。滿足先入後出的棧操作,傳參即...

線段樹(區間合併)HDU 1540

題意 輸入n,m,給定n個相互連通的村莊,有m個操作,d x,表示破壞x村莊使其與相鄰的兩個村莊不相通,r 表示修復上乙個被破壞的村莊,與相鄰的兩個村莊聯通。q x表示與x相連的村莊有多少個。思路 一開始只知道是線段樹,想著肯定得用結構體記錄每個點的資訊,怎麼記錄就不知道了。然後學了線段樹區間合併。...

HDU 1540 線段樹左右區間合併

題目大概的意思就是求當前這個村莊,左右連續的村莊共有幾個,包括自己。思路 比較容易想到的就是把用線段樹劃分的每乙個區間的左右連續區間長度記錄下來,然後嘗試著吧x這個村莊的左右連續並且沒被摧毀的村莊個數連起來,就能得出答案了。具體看 的注釋 include include include includ...