题目链接hdu3308 LCIS
题目大意:给你n个整数,有两种操作,(1)"U A B",表示把第A个数变成B,"Q A B",表示查询区间[A,B]的最长连续上升序列。
解题思路:O(-1)
#include <cstdio>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
#define lz 2*u,l,mid
#define rz 2*u+1,mid+1,r
const int maxn=100005;
int a[maxn];
struct node
{
int lm; ///定义从左边第一个点开始的LCIS
int rm; ///定义以右边最后一个点结束的LCIS
int sm; ///定义整段最大的LCIS
}tree[4*maxn];
void push_up(int u, int l, int r)
{
tree[u].lm=tree[2*u].lm;
tree[u].rm=tree[2*u+1].rm;
tree[u].sm=max(tree[2*u].sm,tree[2*u+1].sm);
int mid=(l+r)>>1;
if(a[mid]<a[mid+1])
{
if(tree[2*u].lm==mid-l+1) tree[u].lm=tree[2*u].lm+tree[2*u+1].lm;
if(tree[2*u+1].rm==r-mid) tree[u].rm=tree[2*u].rm+tree[2*u+1].rm;
int t=tree[2*u].rm+tree[2*u+1].lm;
if(t>tree[u].sm) tree[u].sm=t;
}
}
void build(int u, int l, int r)
{
if(l==r)
{
tree[u].lm=tree[u].rm=tree[u].sm=1;
return ;
}
int mid=(l+r)>>1;
build(lz);
build(rz);
push_up(u,l,r);
}
void Update(int u, int l, int r, int p, int d)
{
if(l==r)
{
a[l]=d; return ;
}
int mid=(l+r)>>1;
if(p<=mid) Update(lz,p,d);
else Update(rz,p,d);
push_up(u,l,r);
}
int Query(int u, int l, int r, int tl, int tr)
{
if(tl<=l&&r<=tr)
{
return tree[u].sm;
}
int mid=(l+r)>>1;
if(tr<=mid) return Query(lz,tl,tr);
else if(tl>mid) return Query(rz,tl,tr);
else
{
int t1=Query(lz,tl,mid);
int t2=Query(rz,mid+1,tr);
int t=max(t1,t2);
if(a[mid]<a[mid+1])
{
t1=min(tree[2*u].rm,mid-tl+1); ///!!!
t2=min(tree[2*u+1].lm,tr-mid); ///!!!
t1+=t2;
}
return max(t,t1);
}
}
int main()
{
int n, m, tcase;
cin >> tcase;
while(tcase--)
{
cin >> n >> m;
for(int i=1; i<=n; i++)
scanf("%d",a+i);
build(1,1,n);
while(m--)
{
char ch[5];
int l, r;
scanf("%s%d%d",ch,&l,&r);
if(ch[0]=='U')
{
l++;
Update(1,1,n,l,r);
}
else
{
l++, r++;
int ans=Query(1,1,n,l,r);
printf("%d\n",ans);
}
}
}
return 0;
}