題意:c++
給定n個整數。 你有兩種操做: U A B:用B替換第A個數。(編號從0開始) Q A B:輸出[a,b]中最長連續嚴格遞增子序列(LCIS)的長度。ui
第一行有一個整數T,表示數據組數。 每組數據以兩個整數n,m(0 <n,m <= 100000)開始。 下一行有n個整數(0 <= val <= 100000)。 spa
接下來的m行每行表示一個操做: U A B(0 <= A,n,0 <= B = 100000) 或 Q A B(0 <= A <= B <n)。code
對於每一個詢問,輸出答案。blog
思路:ci
結點修改以及區間查詢,咱們很容易想到線段樹去實現。同時要求 LCIS 咱們會想到線段樹存儲區間最大值的操做。可是關鍵在於區間如何去更新。string
當左右兩個子樹區間向上合併的時候,父親區間的最大值應該怎麼更新。it
進行分類討論:class
(1)合併時中間部分不會鏈接:左右區間合併時因爲 左子樹的右端值大於等於右子樹的左端值,因此中間部分不能鏈接 (這樣該區間最大值就等於 左右子樹區間的最大值)date
(2)若是要進行鏈接:{咱們就須要記錄某個區間的左右端連續長度,以及左右端點的值}
(i)判斷是否更新 合併區間左右端連續長度,因爲中間鏈接,因此若是左子樹左端連續長度等於其區間長度,(即整個區間連續)則須要更新 合併區間左端長度 = 左子樹左端連續長度+右子樹左端連續長度
同理,合併區間右端長度 = 左子樹右端連續長度+右子樹右端連續長度
(ii) 最後再次判斷是否更新區間最長
code: 其餘具題見代碼註解
#include <bits/stdc++.h> using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const double Pi = acos(-1.0); const double esp = 1e-9; const int inf = 0x3f3f3f3f; const int maxn = 5e5+7; const int maxm = 1e6+7; const int mod = 1e9+7; //區間合併問題 //要求得區間最長lcs,利用線段樹及兩兩拆分 //合併後的最長長度爲記錄,左最長連續,右最長連續,和中間合併後的最長連續 int n,m; struct segmentTree { int arr[maxn]; //區間最大lcis int maxlen[maxn<<2]; //左右邊界值 int ls[maxn<<2]; int rs[maxn<<2]; //左右最大lcis int lmax[maxn<<2]; int rmax[maxn<<2]; //結點從1開始到n int L[maxn<<2],R[maxn<<2]; void init(int n){ for(int i=1;i<=n;i++){ scanf("%d",&arr[i]); } } void build(int l,int r,int p){ L[p] = l; R[p] = r; if(l==r) { lmax[p] = rmax[p] = maxlen[p] = 1; ls[p] = rs[p] = arr[l]; return ; } int mid = (l+r)>>1; build(l,mid,p<<1); build(mid+1,r,p<<1|1); push_up(p); } void push_up(int p){ //對push_up()進行判斷遞推 //(1)左右端點、左右端連續長度賦值,初始區間最大值 ls[p] = ls[p<<1]; rs[p] = rs[p<<1|1]; lmax[p] = lmax[p<<1]; rmax[p] = rmax[p<<1|1]; maxlen[p] = max(maxlen[p<<1],maxlen[p<<1|1]); //(2)中間部分長度是否合併 if(rs[p<<1]<ls[p<<1|1]){ //(2*)判斷是否更新該區間左右端連續最大長度 //(2**)若是左子樹lcis等於其區間長度 if(lmax[p<<1] == (R[p<<1]-L[p<<1]+1)){ lmax[p] += lmax[p<<1|1]; } //(2**)若是右子樹lcis等於其區間長度 if(rmax[p<<1|1] == (R[p<<1|1]-L[p<<1|1]+1)){ rmax[p] += rmax[p<<1]; } //(3)判斷最大長度是否更新:左子樹的右端與右子樹的左端 maxlen[p] = max(maxlen[p],rmax[p<<1] + lmax[p<<1|1]); } } void update(int p,int k,int q){ if(L[p] == R[p]){ //更新結點值 ls[p] = rs[p] = k; return ; } int mid = (L[p]+R[p])>>1; if(q<=mid) update(p<<1,k,q); else update(p<<1|1,k,q); push_up(p); } int query(int ql,int qr,int p){ if(L[p]>=ql && R[p]<=qr){ return maxlen[p]; } int mid = (L[p]+R[p])>>1; int res = 0; if(ql<=mid) res = max(res,query(ql,qr,p<<1)); if(qr>mid) res = max(res,query(ql,qr,p<<1|1)); //(中間區間長度) if(rs[p<<1]<ls[p<<1|1]){ res = max(res,min(mid-ql+1,rmax[p<<1])+min(qr-mid,lmax[p<<1|1])); } return res; } }seg; int main(){ int T; scanf("%d",&T); while(T--){ scanf("%d %d",&n,&m); seg.init(n); seg.build(1,n,1); string s; for(int i=0;i<m;i++){ cin>>s; if(s[0]=='Q'){ int L,R; scanf("%d %d",&L,&R); printf("%lld\n",seg.query(L+1,R+1,1)); }else{ int ith,k; scanf("%d %d",&ith,&k); seg.update(1,k,ith+1); } } } return 0; }