HDU 3308 线段树求区间最长连续上升子序列长度
题意:两种操作,Q L R查询L - R 的最长连续上升子序列长度,U pos val 单点修改值
#include <bits/stdc++.h> #define N 100005 using namespace std; int lcs[N<<2],pre[N<<2],suf[N<<2],arr[N];维护区间lcs长度,以左端点为起点的lcs长度,以右端点为终点的lcs长度,这么做是为了处理区间合并后区间总lcs值的更新 void pushup(int l,int r,int rt) { int m=(l+r)>>1; lcs[rt]=max(lcs[rt<<1],lcs[rt<<1|1]); if(arr[m]<arr[m+1])lcs[rt]=max(lcs[rt],suf[rt<<1]+pre[rt<<1|1]); pre[rt]=pre[rt<<1]; if(pre[rt<<1]==m-l+1&&arr[m]<arr[m+1])pre[rt]+=pre[rt<<1|1]; suf[rt]=suf[rt<<1|1]; if(suf[rt<<1|1]==r-m&&arr[m]<arr[m+1])suf[rt]+=suf[rt<<1]; } void build(int l,int r,int rt) { if(l==r) { suf[rt]=pre[rt]=lcs[rt]=1; return; } int m=(l+r)>>1; build(l,m,rt<<1); build(m+1,r,rt<<1|1); pushup(l,r,rt); } void update(int pos,int val,int l,int r,int rt) { if(l==r) { arr[l]=val; return; } int m=(l+r)>>1; if(pos<=m)update(pos,val,l,m,rt<<1); if(pos>m)update(pos,val,m+1,r,rt<<1|1); pushup(l,r,rt); } int query(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R)return lcs[rt]; int m=(l+r)>>1; int mx=0; if(L<=m)mx=max(mx,query(L,R,l,m,rt<<1)); if(m<R)mx=max(mx,query(L,R,m+1,r,rt<<1|1));//这时的mx只是各子区间的最大值,必须考虑子区间连接之后的状态 int prex=min(R-m,pre[rt<<1|1]); int sufx=min(m-L+1,suf[rt<<1]); if(arr[m]<arr[m+1])mx=max(mx,prex+sufx); return mx; } int main() { int t,n,m; cin>>t; while(t--) { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",arr+i); build(1,n,1); char cmd[10]; int l,r; while (m--) { scanf("%s%d%d",cmd,&l,&r); if(cmd[0]=='U')update(l+1,r,1,n,1); else printf("%d\n",query(l+1,r+1,1,n,1)); } } return 0; }