所谓线段树区间合并就是在查询的时候对线段树的孩子进行合并,合并成一段区间进行操作的合并
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3785 Accepted Submission(s): 1712
1 10 10 7 7 3 3 5 9 9 8 1 8 Q 6 6 U 3 4 Q 0 1 Q 0 5 Q 4 7 Q 3 5 Q 0 2 Q 4 6 U 6 10 Q 0 9
1 1 4 2 3 1 2 5
题意:
给你n个整数,有两种操作,U A B把第A个数变成B,Q A B查询区间[A,B]的最长连续上升序列。
解题分析:
在线段树的节点里保留了端点的值即lval,rval。同时维护左端点最长的上长序列的长度lmx,右端点的最长的下降序列的长度rmx,以及这个区间的最长上升序列的长度mx。在合并区间的时候,如果当前区间的左儿子的lmx等于左儿子的区间长度,那么当前区间的lmx还要加上右儿子的lmx。维护当前区间的rmx也是类似的,当前区间的mx除了在左右儿子的区间中的mx取一个最大值外,还要注意,如果左儿子的右端点小于右儿子的左端点那么当前区间的mx还有可能是左儿子的rmx加上右儿子的lmx。
在查询的时候,要注意,如果查询的范围是在当前区间的左右儿子里,并且左儿子的右端点小于右儿子的左端点,那么不能直接取左儿子的rmx加上右儿子的lmx,因为有可能查询的范围的长度就已经小于左儿子的rmx加上右儿子的lmx,所以要加上一个判断。
(代码风格更新前,没有在线段树节点里保存端点的值)之前做得比较复杂,在节点里还保存了这个区间端点的值,然后在合并的时候去比较,后来在网上看到一种作法,更新到叶子结点的时候直接对数组y进行操作。合并的时候,直接对数组y里的元素进行比较。
代码:
/*代码风格更新后*/
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define MID(a,b) (a+((b-a)>>1))
const int N=1e5+5;
struct node
{
int lft,rht;
int lval,rval;
int lmx,rmx,mx;
int mid(){return MID(lft,rht);}
int len(){return rht-lft+1;}
};
int y[N],n,m;
struct Segtree
{
node tree[N*4];
void up(int ind)
{
tree[ind].lmx=tree[LL(ind)].lmx;
tree[ind].rmx=tree[RR(ind)].rmx;
tree[ind].lval=tree[LL(ind)].lval;
tree[ind].rval=tree[RR(ind)].rval;
tree[ind].mx=max(tree[LL(ind)].mx,tree[RR(ind)].mx);
if(tree[LL(ind)].rval<tree[RR(ind)].lval)
{
if(tree[LL(ind)].len()==tree[LL(ind)].lmx)
tree[ind].lmx+=tree[RR(ind)].lmx;
if(tree[RR(ind)].len()==tree[RR(ind)].rmx)
tree[ind].rmx+=tree[LL(ind)].rmx;
tree[ind].mx=max(tree[ind].mx,tree[LL(ind)].rmx+tree[RR(ind)].lmx);
}
tree[ind].mx=max(tree[ind].mx,max(tree[ind].lmx,tree[ind].rmx));
}
void build(int lft,int rht,int ind)
{
tree[ind].lft=lft; tree[ind].rht=rht;
if(lft==rht)
{
tree[ind].lval=tree[ind].rval=y[lft];
tree[ind].lmx=tree[ind].rmx=tree[ind].mx=1;
}
else
{
int mid=tree[ind].mid();
build(lft,mid,LL(ind));
build(mid+1,rht,RR(ind));
up(ind);
}
}
void updata(int pos,int ind,int valu)
{
int lft=tree[ind].lft,rht=tree[ind].rht;
if(lft==rht) tree[ind].lval=tree[ind].rval=valu;
else
{
int mid=tree[ind].mid();
if(pos<=mid) updata(pos,LL(ind),valu);
else updata(pos,RR(ind),valu);
up(ind);
}
}
int query(int st,int ed,int ind)
{
int lft=tree[ind].lft,rht=tree[ind].rht;
if(st<=lft&&rht<=ed) return tree[ind].mx;
else
{
int mid=tree[ind].mid();
if(ed<=mid) return query(st,ed,LL(ind));
else if(st>mid) return query(st,ed,RR(ind));
else
{
int tmp1=0,tmp2=0;
int mx1=query(st,ed,LL(ind)),mx2=query(st,ed,RR(ind));
if(tree[LL(ind)].rval<tree[RR(ind)].lval)
{
tmp1=min(mid-st+1,tree[LL(ind)].rmx);
tmp2=min(ed-mid,tree[RR(ind)].lmx);
}
return max(max(mx1,mx2),tmp1+tmp2);
}
}
}
}seg;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++) scanf("%d",&y[i]);
seg.build(0,n-1,1);
while(m--)
{
char cmd[5];
int a,b;
scanf("%s%d%d",cmd,&a,&b);
if(cmd[0]=='Q') printf("%d\n",seg.query(a,b,1));
else seg.updata(a,1,b);
}
}
return 0;
}