题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:一串数字,可以修改某一个位置的值,无限定查询,查询某一区间内的最长单调递增字串(是子串,而不是子序列;字串是连续的,子序列不需要连续)的长度。
为了求区间内的最长单调递增子串的长度,我们除了用midGo[]数组维护某一区间内的最长单调递增字串的长度外,还需要开辟两个数组leftGo[]和rightGo[],分别记录区间内从最左端开始的最长单调递增子串的长度和从最右端结束的最长单调递增子串的长度。
详见代码:
#include <iostream> #include <stdlib.h> #include <stdio.h> using namespace std; #define Maxn 100005 #define lx (x<<1) #define rx ((x<<1)|1) #define MID ((l + r)>>1) int A[Maxn]; int leftGo[Maxn<<2]; int rightGo[Maxn<<2]; int midGo[Maxn<<2]; //fastmax int _max(int x, int y) { return (((y-x)>>(32-1))&(x^y))^y; } void pushUp(int l,int r,int x) { leftGo[x] = leftGo[lx]; rightGo[x] = rightGo[rx]; midGo[x] = 0; if(A[MID] < A[MID+1]) { midGo[x] = rightGo[lx] + leftGo[rx]; if(leftGo[x] == MID-l+1) leftGo[x] += leftGo[rx]; if(rightGo[x] == r - MID) rightGo[x] += rightGo[lx]; } midGo[x] = _max(midGo[x],_max(midGo[lx],midGo[rx])); } void build(int l,int r,int x) { if(l == r) { midGo[x] = leftGo[x] = rightGo[x] = 1; return; } build(l,MID,lx); build(MID+1,r,rx); pushUp(l,r,x); } void update(int p,int d,int l,int r,int x) { if(l == r) { A[l] = d; return; } if(p<=MID) update(p,d,l,MID,lx); else update(p,d,MID+1,r,rx); pushUp(l,r,x); } int query(int L,int R,int l,int r,int x) { if(L<=l && r<=R) { return midGo[x]; } //完全在左边 if(R<=MID) query(L,R,l,MID,lx); //完全在右边 else if(MID<L) query(L,R,MID+1,r,rx); //一部分在左边,一部分在右边 else { int temp = 0; if(A[MID] < A[MID+1]) temp = min(rightGo[lx],MID-L+1) + min(leftGo[rx],R - MID); int t1 = query(L,R,l,MID,lx); int t2 = query(L,R,MID+1,r,rx); return _max(temp,_max(t1,t2)); } } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); #endif int t; int n,m; char op; int a,b; scanf(" %d",&t); while(t--) { scanf(" %d %d",&n,&m); for(int i=1;i<=n;i++) scanf(" %d",&A[i]); build(1,n,1); for(int i=1;i<=m;i++) { scanf(" %c %d %d",&op,&a,&b); if(op == 'Q') { int ans = query(a+1,b+1,1,n,1); printf("%d\n",ans); } else if(op == 'U') update(a+1,b,1,n,1); } } return 0; }