题目:http://acm.hdu.edu.cn/showproblem.php?pid=3308
题意:可以单点更新,找区间最长连续子序列。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000010
using namespace std;
int n,m,s[N];
struct Tree{
int l,r,c;//左右边界与连续的长度
int ln,rn;//左右边界的值
int ls,rs,ms;//左右最大LCIS,和区间最大LCIS
}tree[4*N];
void push_up(int i){
tree[i].ls = tree[2*i].ls;
tree[i].rs = tree[2*i+1].rs;
tree[i].ln = tree[2*i].ln;
tree[i].rn = tree[2*i+1].rn;
tree[i].ms = max(tree[2*i].ms,tree[2*i+1].ms);
if(tree[2*i].rn<tree[2*i+1].ln){ //如果左子树的右边界值小于右子树的左边界值,要合并左子树的右边界和右子树的左边界
if(tree[2*i].ls == tree[2*i].c)
tree[i].ls+=tree[2*i+1].ls;
if(tree[2*i+1].rs == tree[2*i+1].c)
tree[i].rs+=tree[2*i].rs;
tree[i].ms = max(tree[i].ms,tree[2*i].rs+tree[2*i+1].ls);
}
}
void build(int t,int l,int r){
tree[t].l=l;
tree[t].r=r;
tree[t].c=r-l+1;
if(l==r){
tree[t].ln=tree[t].rn=s[l];
tree[t].ls=tree[t].rs=tree[t].ms=1;
return;
}
int mid=(l+r)>>1;
build(2*t,l,mid);
build(2*t+1,mid+1,r);
push_up(t);
}
void update(int t,int pos,int val){
if(tree[t].l==tree[t].r){
tree[t].ln=tree[t].rn=val;
return;
}
int mid=(tree[t].l+tree[t].r)>>1;
if(pos<=mid)
update(2*t,pos,val);
else
update(2*t+1,pos,val);
push_up(t); //向上维护
}
int query(int t,int l,int r){
if(l<=tree[t].l&&r>=tree[t].r)
return tree[t].ms;
int mid=(tree[t].l+tree[t].r)>>1,ans=0;
if(l<=mid) ans=max(ans,query(2*t,l,r));
if(r>mid) ans=max(ans,query(2*t+1,l,r));
if(tree[2*t].rn < tree[2*t+1].ln)
ans=max(ans, min(mid-l+1,tree[2*t].rs) + min(r-mid,tree[2*t+1].ls));
//不能超过边界啊,所以右边要小于r-mid,左边同理。
return ans;
}
int main(){
int t;
char ss[3];
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&s[i]);
build(1,1,n);
while(m--){
int a,b;
scanf("%s%d%d",ss,&a,&b);
if(ss[0]=='Q')
printf("%d\n",query(1,a+1,b+1));
else
update(1,a+1,b);
}
}
return 0;
}