鏈結lcis
題意 :
查詢區間 中最長的連續上公升序列,支援單點修改。
思路:
線段樹+區間合併,主要在於 pushup 和query 的變化。
需要記錄每個區間左右端點的數值,和以左右端點為起點的最長合法區間。
先看看 pushup ,當前區間的最大合法區間 首先可以由左右區間的最大值更新而來,同時如果左區間最右邊的數比右區間最左邊的數小,是可以進行一些合併操作的。具體看**
void
pushup
(int rt,
int m)
if(s[rt<<1|
1].rcnt==
(m>>1)
) s[rt]
.ncnt=
max(s[rt]
.ncnt,s[rt<<1]
.rcnt+s[rt<<1|
1].lcnt)
;//最長區間可能為兩區間合併部分
}}
update 部分沒有很大的變化,注意更新後要把值初始化為 1.
void
update
(int id,
int v,
int l,
int r,
int rt)
int mid=
(l+r)
>>1;
if(id<=mid)
update
(id,v,l,mid,rt<<1)
;if(id>mid)
update
(id,v,mid+
1,r,rt<<1|
1);pushup
(rt,r-l+1)
;}
最後就是 查詢操作了,這裡最大合法區間除了可能單獨在左右子區間,還有可能在兩個部分。
int
query
(int l,
int r,
int l,
int r,
int rt)
return ans;
}
完整**
#include
#include
#include
#include
#include
#include
#include
using
namespace std;
typedef
long
long ll;
const
int maxn=
1e5+7;
int t;
struct nodes[maxn<<2]
;void
pushup
(int rt,
int m)
if(s[rt<<1|
1].rcnt==
(m>>1)
) s[rt]
.ncnt=
max(s[rt]
.ncnt,s[rt<<1]
.rcnt+s[rt<<1|
1].lcnt);}
}void
build
(int l,
int r,
int rt)
int m=
(l+r)
>>1;
build
(l,m,rt<<1)
;build
(m+1
,r,rt<<1|
1);pushup
(rt,r-l+1)
;}void
update
(int id,
int v,
int l,
int r,
int rt)
int mid=
(l+r)
>>1;
if(id<=mid)
update
(id,v,l,mid,rt<<1)
;if(id>mid)
update
(id,v,mid+
1,r,rt<<1|
1);pushup
(rt,r-l+1)
;}intquery
(int l,
int r,
int l,
int r,
int rt)
return ans;
}int
main()
}}
HDU 3308 LCIS(線段樹合併)
維護乙個區間的包含最左的元素的lcis,包含最右元素的lcis,以及整個區間的lcis,然後pushup的時候就更新這三個值就行了。注意要考慮左右兒子可以 接 起來的情況等等 查詢的時候要注意,也要考慮左右可以 接 起來時候,不過還要注意,有可能左右兒子邊界的已經 越界了 就是超過了查詢範圍,還要取...
HDU 3308 LCIS(線段樹區間合併)
給你乙個序列,現在進行一些操作,一種是詢問某一段最長連續上公升子串行 lcis 的長度,另乙個就是修改某個點的值 區間合併的簡單題 這裡的區間合併,要判斷的是左兒子最右邊的值和右兒子最左邊的值的關係,那麼我們這道題要維護的東西就有 最左端開始的lcis,包括最右端的lcis,該區間的lcis,最左邊...
HDU 3308 LCIS 線段樹 區間合併
題目鏈結 前言 最近在做線段樹的練習,對於區間合併問題不是很清楚,花了好久才把線段樹的區間合併問題理清楚,所以把學習的過程記錄下來,建議手動建樹並模擬測試用例 題目大意 有乙個陣列,求這個陣列中最長的單調連續遞增序列的長度 題解 見一下注釋 樹結點的定義 有該結點的左端點 右端點 有該結點對應區間的...