做kuangbin線段樹專題的時候遇到的題目,感覺這是一道非常有趣的題目。線段樹的題目做的比較少,沒有見過這種通過線段樹在區間上做文章的題目,感覺做完這個題目之後加深了對線段樹左右孩子所覆蓋的區間之間的關係的認識。
題意:1-n個地道,m個次操作,d代表摧毀第i個地道,q代表查詢包含第i個地道的最大連續地道數目,並輸出。r代表修復最近摧毀的那個地道;
解題的關鍵思路&過程:這個題目一開始我完全想不到利用左右孩子所覆蓋的區間之間的關係來做到查詢最大連續區間,感覺這個題目和線段樹基本操作的對線段樹的所利用的性質不同,這裡充分利用了相鄰的節點之間區間都是連續的這個性質,這個雖然是個基本的性質,但是平時著重與對左右孩子之間關係利用,有點忽視非相同父節點的同一層的葉子節點之間的關係(菜~_~)。這個題目利用tree[i].ll和tree[i].rr這兩個元素分別記錄這個節點所包含的區間從最左邊起的最大連續區間,和從最右邊起的最大連續區間。
想一下為什麼要這麼做呢??
感覺這正是巧妙的地方,正是這樣就可以求得同一層葉子節點的最大連續區間,同層的最大連續區間只可能是你包含你查詢的那個地道i的區間的節點,加上左邊那個節點的的最左邊起的最大連續區間或著加上右邊那個節點的從最右邊起的最大連續區間;
再想一下為什麼最大連續區間只能是最多相鄰兩個節點的加和呢?因為如果當前層有三個節點的區間都連續,那查詢時一定會在當前層的上一層節點就結束,不會再查到此層。
#include#include#include#includeusing namespace std;
struct nodetree[4*50050];
void build(int i,int l,int r)
build(i<<1,l,(int)floor((r+l)/2.0));
build((i<<1)+1,(int)floor((r+l)/2.0)+1,r);
}void update(int i,int x,int cnt)
int mid=(tree[i].l+tree[i].r)>>1;
if(mid>=x)
else
if(tree[(i<<1)].ll+tree[(i<<1)+1].rr==tree[i].len)
tree[i].ll=tree[i].rr=tree[i].len;
else
}int que(int i,int x)
if(tree[i].rr)
} if(tree[i].ll)
if(tree[i].rr)
if(tree[i].l==tree[i].r)
return 0;
int mid=(tree[i].l+tree[i].r)>>1;
if(mid>=x)
return que(i<<1,x);
else
return que((i<<1)+1,x);
}int main()
else if(c[0]=='q')
else
} }return 0;
}
線段樹 區間合併 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...