題目鏈結
給定一段區間求 最長連續上公升序列長度
兩個操作 q 操作區間查詢最長連續上公升子串行 u操作 單點更新
一般的區間合併問題,我算是發現了,都要維護三個基本引數
從左端開始的 從右端開始的 中間最大的
所以這個題 也不例外 維護左端開始的最長 和右端結束的最長 還有區間最長
然後 在記錄一下這個區間的左右端點值 在合併的時候 需要比較
主要是如何pushup 首先往上更新的時候 最長的肯定是左右的最大的
然後 左端 判斷是否貫穿 貫穿就是 左兒子右端點大於 右兒子左端點 這個時候
左端連續 要加上右兒子的左端連續
同理 右端連續也是這樣 然後就可以了
然後 查詢的時候 同樣遵守之前的道理 你的區間要是分開的時候要判斷一下
你分開的區間 左兒子的右端點和右兒子的左端點的大小比較一下
如果可以連續 我們比較一下 左右兒子的最大和 還有這個區間大小
就是你不能超過這個區間的大小和之前的找01 最長1的那個是乙個道理
然後比較乙個最大值就可以了
ps : 總感覺最正統的線段樹往下遞迴的時候 都應該分三個寫誒 以前兩個的寫法有點偷懶
#include
#define n 100005
using
namespace std;
struct node
;node shu[n<<2]
;int a[n]
;void
pushup
(int rt)
shu[rt]
.lsum = shu[rt<<1]
.lsum;
if(shu[rt]
.lsum ==
(shu[rt<<1]
.r - shu[rt<<1]
.l+1
)&& shu[rt<<1]
.rs1]
.ls)
shu[rt]
.rsum = shu[rt<<1|
1].rsum;
if(shu[rt]
.rsum ==
(shu[rt<<1|
1].r - shu[rt<<1|
1].l+1
)&& shu[rt<<1]
.rs1]
.ls)
}void
build
(int rt,
int l,
int r)
int mid =
(l+r)
>>1;
build
(rt<<
1,l,mid)
;build
(rt<<1|
1,mid+
1,r)
;pushup
(rt);}
void
update
(int rt,
int pos,
int val)
int mid =
(l+r)
>>1;
if(pos<=mid)
update
(rt<<
1,pos,val)
;else
update
(rt<<1|
1,pos,val)
;pushup
(rt);}
intfind
(int rt,
int l,
int r)
int ans =0;
int mid =
(l+r)
>>1;
if(l<=mid) ans =
max(ans,
find
(rt<<
1,l,r));
if(r>mid) ans =
max(ans,
find
(rt<<1|
1,l,r));
if(shu[rt<<1]
.rs < shu[rt<<1|
1].ls && l<=mid && r>mid )
return ans;
}int
main()
memset
(shu,0,
sizeof
(shu));
build(1
,1,n);
while
(m--
)else}}
}
hdu 3308 線段樹單點更新 區間合併
學到兩點 1 以區間端點為開始 結束的最長.似乎在dp也常用這種思想 2 分類的時候,明確標準逐層分類,思維格式 條件一成立 else else else 上面的這種方式很清晰,如果直接想到那種情況iif 條件一 條件二 就寫,很容易出錯而且把自己搞亂,或者情況不全,我就因為這wa了幾次 3 wa了...
HDU 3308 線段樹。。最長連續上公升子串行
這個被 notonlysuccess 歸類為區間合併 想來區間合併的題 pushup 不但更新的時候會用到,左右兩個孩子得到的結果也要用 pushup 處理,就換了一下pushup的形式。爽 寫著寫著。不知不覺這巨集就變的越來越多了。include include include include i...
HDU 3308 LCIS(線段樹合併)
維護乙個區間的包含最左的元素的lcis,包含最右元素的lcis,以及整個區間的lcis,然後pushup的時候就更新這三個值就行了。注意要考慮左右兒子可以 接 起來的情況等等 查詢的時候要注意,也要考慮左右可以 接 起來時候,不過還要注意,有可能左右兒子邊界的已經 越界了 就是超過了查詢範圍,還要取...