題目鏈接:hdu3308
/*hdu3308 LCIS 線段樹區間合並 題目大意: 求一段區間內的連續最長 思路: 記錄以區間左端點開始的LCIS,以區間右端點結尾的LCIS以及整個區間的LCIS, 區間左端點的數和區間右端點的數。 更新和建樹操作都應更到葉子節點,只有葉子節點的信息時可以直接得出,然後 遞歸回到父節點,父節點可以根據左右孩子的信息來更新自己 */ #include#include #include #include #include using namespace std; #define lson l, m, rt<<1 #define rson m+1, r, rt<<1|1 const int N = 200005; struct node { int lnum, rnum;//區間最左端的數和最右端的數 int llen;//以左端點開始的連續最長 int rlen;//以右端點結束的連續最長 int mlen;//區間內的連續最長 }s[N<<2]; void pushup(int rt, int m) { s[rt].lnum = s[rt<<1].lnum; s[rt].rnum = s[rt<<1|1].rnum; s[rt].llen = s[rt<<1].llen; s[rt].rlen = s[rt<<1|1].rlen; s[rt].mlen = max(s[rt<<1].mlen, s[rt<<1|1].mlen); if(s[rt<<1].rnum < s[rt<<1|1].lnum)//左兒子的右端點<右兒子的左端點 { if(s[rt].llen == m - (m>>1))//左兒子表示的區間裡的所有數,連續遞增 s[rt].llen += s[rt<<1|1].llen; if(s[rt].rlen == (m>>1))//右兒子表示的區間裡的所有數,連續遞增 s[rt].rlen += s[rt<<1].rlen; s[rt].mlen = max(s[rt<<1].rlen + s[rt<<1|1].llen, s[rt].mlen);//左兒子的右連續長度+右兒子的左連續長度 } } void build(int l, int r, int rt) { s[rt].llen = s[rt].rlen = s[rt].mlen = 1; if(l == r) { scanf("%d",&s[rt].lnum); s[rt].rnum = s[rt].lnum; return; } int m = (l+r) >> 1; build(lson); build(rson); pushup(rt, r-l+1); } void update(int pos, int num, int l, int r, int rt) { if(l == pos && pos == r) { s[rt].llen = s[rt].rlen = s[rt].mlen = 1; s[rt].lnum = s[rt].rnum = num; return; } int m = (l+r) >> 1; if(pos <= m) update(pos, num, lson); else update(pos, num, rson); pushup(rt, r-l+1); } int query(int L, int R, int l, int r, int rt) { if(L <= l && r <= R) { return s[rt].mlen; } int m = (l+r) >> 1; int ans = 0; if(L <= m) ans = max(ans, query(L, R, lson)); if(m < R) ans = max(ans, query(L, R, rson)); if(s[rt<<1].rnum < s[rt<<1|1].lnum) ans = max(ans, min(m-L+1,s[rt<<1].rlen) + min(R-m, s[rt<<1|1].llen) ); return ans; } int main() { int T,n,m; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); build(1, n, 1); char a[2]; int x,y; while(m--) { scanf("%s%d%d",a,&x,&y); if(a[0] == 'Q') printf("%d\n",query(x+1, y+1, 1, n, 1)); if(a[0] == 'U') update(x+1, y, 1, n, 1); } } return 0; }