刚刚做了两道LCIS,碰到这道线段树,脑抽了似的写 线段树+dp(LCIS),贡献一发TLE。
才想到要区间合并,query函数写了好久。下面有详细注释,参见代码吧~~欢迎点赞,欢迎卖萌~~
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3308
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 111111
#define lson rt<<1,s,m
#define rson rt<<1|1,m+1,e
using namespace std;
struct node{
int lv,rv; // 维护一个区间的左端点值和右端点值。
int lm,rm,sm; //左LCIS,右LCIS,整个区间LCIS。
}tre[N<<2];
void pushup(int rt,int m) //区间合并。
{
tre[rt].lm=tre[rt<<1].lm;
tre[rt].rm=tre[rt<<1|1].rm;
tre[rt].lv=tre[rt<<1].lv;
tre[rt].rv=tre[rt<<1|1].rv;
tre[rt].sm=max(tre[rt<<1].sm,tre[rt<<1|1].sm); //1~~
//左儿子的右端点值小于右儿子的左端点值,最长LCIS可能在中间区域。
if(tre[rt<<1].rv < tre[rt<<1|1].lv)
{
tre[rt].sm=max(tre[rt].sm,tre[rt<<1].rm+tre[rt<<1|1].lm);//2~~
if(tre[rt<<1].lm == m-(m>>1))
tre[rt].lm += tre[rt<<1|1].lm;
if(tre[rt<<1|1].rm == (m>>1))
tre[rt].rm += tre[rt<<1].rm;
}
}
void build(int rt,int s,int e)
{
if(s==e)
{
scanf("%d",&tre[rt].lv);
tre[rt].rv=tre[rt].lv;
tre[rt].lm=tre[rt].rm=tre[rt].sm=1;
return ;
}
int m=(s+e)>>1;
build(lson);
build(rson);
pushup(rt,e-s+1);
}
void update(int p,int v,int rt,int s,int e)
{
if(s==e)
{
tre[rt].lv=tre[rt].rv=v; //端点更新。
return ;
}
int m=(s+e)>>1;
if(p<=m) update(p,v,lson);
else update(p,v,rson);
pushup(rt,e-s+1);
}
int query(int l,int r,int rt,int s,int e)
{
if(l<=s && e<=r)
return tre[rt].sm;
int m=(s+e)>>1;
if(r<=m) return query(l,r,lson);
else if(l>m) return query(l,r,rson);
else
{
int ans=-1;
if(tre[rt<<1].rv < tre[rt<<1|1].lv) //~~
{
//左儿子右LCIS的左边界。
int L=m-tre[rt<<1].rm+1;
//右儿子左LCIS的右边界。
int R=m+1+tre[rt<<1|1].lm-1;
ans=min(R,r)-max(L,l)+1;
}
return max(query(l,m,lson),max(query(m+1,r,rson),ans));
}
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
int n,m;
scanf("%d%d",&n,&m);
build(1,0,n-1);
while(m--)
{
char op[5];
scanf("%s",op);
if(op[0]=='Q')
{
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(l,r,1,0,n-1));
}
else
{
int p,v;
scanf("%d%d",&p,&v);
update(p,v,1,0,n-1);
}
}
}
return 0;
}