LCIS --线段树区间合并

所谓线段树区间合并就是在查询的时候对线段树的孩子进行合并,合并成一段区间进行操作的合并

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3785    Accepted Submission(s): 1712


Problem Description
Given n integers.
You have two operations:
U A B: replace the Ath number by B. (index counting from 0)
Q A B: output the length of the longest consecutive increasing subsequence (LCIS) in [a, b].
 

Input
T in the first line, indicating the case number.
Each case starts with two integers n , m(0<n,m<=105).
The next line has n integers(0<=val<=105).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=105)
OR
Q A B(0<=A<=B< n).
 

Output
For each Q, output the answer.
 

Sample Input
   
   
   
   
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
 

Sample Output
   
   
   
   
1 1 4 2 3 1 2 5
 

Author
shǎ崽
 

Source
HDOJ Monthly Contest – 2010.02.06
 
4

题意:

给你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;
}

你可能感兴趣的:(LCIS --线段树区间合并)