HDU-3308 LCIS(区间合并)
题目大意:给一个整数序列,m次询问,每次询问某个区间中最长连续上升子序列的长度。
题目分析:线段树区间合并。维护以区间左端开头的、以区间右端点结尾的和区间最长的上升连续序列。
代码如下:
# include<bits/stdc++.h> using namespace std; # define LL long long # define mid (l+(r-l)/2) const int N=100000; int w[N+5]; int len[N*4+5]; int l1[N*4+5],l3[N*4+5]; int r1[N*4+5],r3[N*4+5]; void pushUp(int rt,int l,int r) { len[rt]=0; if(w[mid]<w[mid+1]){ if(r1[rt<<1]==mid) r1[rt]=r1[rt<<1|1]; else r1[rt]=r1[rt<<1]; if(l1[rt<<1|1]==mid+1) l1[rt]=l1[rt<<1]; else l1[rt]=l1[rt<<1|1]; if(r1[rt<<1|1]-l1[rt<<1]+1>len[rt]){ len[rt]=r1[rt<<1|1]-l1[rt<<1]+1; l3[rt]=l1[rt<<1]; r3[rt]=r1[rt<<1|1]; } }else{ l1[rt]=l1[rt<<1|1]; r1[rt]=r1[rt<<1]; } if(r1[rt]-l+1>len[rt]){ len[rt]=r1[rt]-l+1; l3[rt]=l,r3[rt]=r1[rt]; } if(r-l1[rt]+1>len[rt]){ len[rt]=r-l1[rt]+1; l3[rt]=l1[rt],r3[rt]=r; } if(r3[rt<<1]-l3[rt<<1]+1>len[rt]){ len[rt]=r3[rt<<1]-l3[rt<<1]+1; l3[rt]=l3[rt<<1]; r3[rt]=r3[rt<<1]; } if(r3[rt<<1|1]-l3[rt<<1|1]+1>len[rt]){ len[rt]=r3[rt<<1|1]-l3[rt<<1|1]+1; l3[rt]=l3[rt<<1|1]; r3[rt]=r3[rt<<1|1]; } } void build(int rt,int l,int r) { if(l==r){ len[rt]=1; l1[rt]=r1[rt]=l; l3[rt]=r3[rt]=l; }else{ build(rt<<1,l,mid); build(rt<<1|1,mid+1,r); pushUp(rt,l,r); } } void update(int rt,int l,int r,int p,int x) { if(l==r){ w[l]=x; }else{ if(p<=mid) update(rt<<1,l,mid,p,x); if(p>mid) update(rt<<1|1,mid+1,r,p,x); pushUp(rt,l,r); } } int query(int rt,int l,int r,int L,int R) { if(L<=l&&r<=R) return len[rt]; if(R<=mid) return query(rt<<1,l,mid,L,R); if(L>mid) return query(rt<<1|1,mid+1,r,L,R); int li=query(rt<<1,l,mid,L,R); int ri=query(rt<<1|1,mid+1,r,L,R); int res=max(li,ri); if(w[mid]<w[mid+1]) res=max(res,min(R,r1[rt<<1|1])-max(L,l1[rt<<1])+1); return res; } int main() { int T,n,m; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;++i) scanf("%d",w+i); build(1,0,n-1); int a,b; char op[2]; while(m--) { scanf("%s%d%d",op,&a,&b); if(op[0]=='Q'){ printf("%d\n",query(1,0,n-1,a,b)); }else if(op[0]=='U') update(1,0,n-1,a,b); } } return 0; }