線段樹基礎之區間合併HDU1540

2021-09-26 06:26:53 字數 3494 閱讀 5679

參考部落格

?(巨佬i了

題目大意:給出m個城市在按直線排列,用道路連線起來,現在可以把任意的城市炸裂或者修復,問乙個城市連線了多少其他城市(包括自身)

先來講講自己初學對區間合併的理解

tree陣列記錄下區間l,r,並且記錄區間內連續字首1的數量(我記為ll),和連續字尾1的數量(我記為rr)

(sample1 :1101 那麼他的字首就是2,字尾就是1)

(sample2 :11111 字首是5,字尾是5)

給出乙個區間[1,7],它是由區間[1,4],[5,7]合成的,

那麼[1,7]區間的字首1到底有多少呢?肯定是包含了[1,4]的字首1

但是萬一[1,4]全是1呢?

那麼這時候就要加上[5,7]的字首1數量了

字尾1同理

voidpu(

int rt)

建樹是沒有什麼區別的,只是根據題意定義的,在這邊把葉子節點全部定義為1(因為長度為1的線段肯定最大也就1,並且初始所有城市都是完好的)

void

build

(int rt,

int l,

int r)

int mid=

(l+r)

>>1;

build

(lson)

;build

(rson);pu

(rt)

;}

更新也沒有什麼難度,要修改的只有一座城市,只要遞迴找到這座城市並賦值為0,然後向上更新就可以了

void

update

(int p,

int x,

int rt,

int l,

int r)

int mid=

(tree[rt]

.l+tree[rt]

.r)>>1;

if(p<=mid)

update

(p,x,rt<<

1,l,r)

;else

update

(p,x,rt<<1|

1,l,r);pu

(rt)

;}

最難的就是查詢了,理解了好久

我們一直記錄的是乙個區間的字首1和字尾1的數量,那麼我們現在題目問的是乙個城市連線其他城市的數量,這有什麼關係呢?

sample:110101

現在給出7個城市,我們要求第四個城市的連線情況,動態來看就是從這個點往左往右出發,直到碰到0停止,也就是要求乙個最長的連續1區間

我們查詢的時候一定是查到這個點被包含在連續區間內

一開始查1,7,發現4並不在他的連續區間([1,2],[7,7])內,就繼續查左子樹(因為4在左子樹上)

然後查1,4,發現4在他的連續區間內([1,2],[4,4]),那麼此時就可以直接退出了!

找到左子樹的字尾和右子樹的字首加起來就可以了

int

query

(int p,

int rt,

int l,

int r)

int mid=

(tree[rt]

.l+tree[rt]

.r)>>1;

if(p<=mid)

else

}

/**

* author1: low-equipped w_udixixi

* author2: sher丶lock

* date :2019-08-17

**/#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define pb push_back

#define rep(x,a,b) for (int x=a;x<=b;x++)

#define repp(x,a,b) for (int x=a;x#define pi 3.14159265358979323846

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

#define lson rt<<1,l,mid

#define rson rt<<1|1,mid+1,r

using namespace std;

const

int maxn=

2e6+7;

const

int inf=

1e9;

struct node

tree[maxn]

;stack<

int> s;

voidpu(

int rt)

if(tree[rt<<1|

1].rr==tree[rt<<1|

1].r-tree[rt<<1|

1].l+1)}

void

build

(int rt,

int l,

int r)

int mid=

(l+r)

>>1;

build

(lson)

;build

(rson);pu

(rt);}

void

update

(int p,

int x,

int rt,

int l,

int r)

int mid=

(tree[rt]

.l+tree[rt]

.r)>>1;

if(p<=mid)

else

pu(rt);}

intquery

(int p,

int rt,

int l,

int r)

int mid=

(tree[rt]

.l+tree[rt]

.r)>>1;

if(p<=mid)

else

}int

main()

else

if(s[0]

=='q'

)else

if(s[0]

=='r')}

}return0;

}

感覺這只是乙個區間合併的小題,稍微寫一下增長一下理解吧,歡迎指出錯誤!

線段樹 區間合併 HDU 1540

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

線段樹(區間合併)HDU 1540

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

線段樹 區間合併

hdu 1540 tunnel wa re 詳細見 include include include include include define max 50010 define lson l,m,k 1 define rson m 1,r,k 1 1 using namespace std typ...