由于这几天学算法的情绪高涨,于是就复习了之前学的线段树,这进一步加深了对线段树的理解,顺便记录一下自己的心得:
1,做线段树题首先要考虑的是线段树中节点的属性,比如左右边界,区间和,在该区间插入的值,延迟标记,等等。
2,弄清楚孩子节点的更新对父亲节点的影响,父亲节点的更新对孩子节点的影响,从而设计好push_up()和push_down()函数。
3,在弄清前两步的基础上设计好build(),updata(),Quary(),函数,这三个函数何时需要调用push_up和push_down 函数为该部分的重点,一定不要乱了顺序
4,如果前三个步骤都得到合理解决,那么线段树问题也就不是什么问题了。。。
该题的题意就是,给你一段数,然后给你两种操作,Q表示查询一个区间的最大连续递增序列的长度,U表示改变某一个位置的值。
下面根据我上面的四个步骤一一分析一下:
1,节点属性 L,R,lsum,rsum,msum:分别表示该节点左右边界,左最长递增长度,右最长递增长度,该区间的最长递增长度
2,经过分析该题只涉及到孩子节点更新对父节点的影响,因此只需要设计push_up函数
3,build()设计很简单,updata()的设计类似于线段树插点问线的更新,最难的也是该题的难点就是Quary()的设计需要注意的是:查询时有时需要对结果进行合并。
4,分析结束。
AC代码:
#include <iostream>
#include<string.h>
#include<algorithm>
#include<cstdio>
#define CLR(arr,val) memset(arr,val,sizeof(arr))
#define N 100010
using namespace std;
void in(int &a)
{
char ch;
while((ch=getchar())<'0'||ch>'9');
for( a=0;ch>='0'&&ch<='9';ch=getchar()) a=a*10+ch-'0';
}
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
typedef struct{
int L;
int R;
int lsum;
int rsum;
int msum;
}Tree;
Tree Node[N<<2];
int a[N];
void push_up(int rt,int s){
Node[rt].lsum=Node[rt<<1].lsum;
Node[rt].rsum=Node[rt<<1|1].rsum;
Node[rt].msum=max(Node[rt<<1].msum,Node[rt<<1|1].msum);
if(a[Node[rt<<1].R]<a[Node[rt<<1|1].L]){
if(Node[rt<<1].lsum==(s-(s>>1))) Node[rt].lsum+=Node[rt<<1|1].lsum;
if(Node[rt<<1|1].rsum==(s>>1)) Node[rt].rsum+=Node[rt<<1].rsum;
Node[rt].msum=max(Node[rt].msum,Node[rt<<1].rsum+Node[rt<<1|1].lsum);
}
}
void build(int l,int r,int rt){
Node[rt].L=l;
Node[rt].R=r;
if(l==r){
in(a[r]);
Node[rt].lsum=Node[rt].rsum=Node[rt].msum=1;
return;
}
int m=(l+r)>>1;
build(lson);
build(rson);
push_up(rt,r-l+1);
}
void updata(int p,int l,int r,int rt)
{
if(r==l) return;
int m=(l+r)>>1;
if(p<=m) updata(p,lson);
else updata(p,rson);
push_up(rt,r-l+1);
}
int Quary(int L,int R,int l,int r,int rt){
if(l==L&&r==R) return Node[rt].msum;
int m=(l+r)>>1;
if(L>m) return Quary(L,R,rson);
else if(R<=m) return Quary(L,R,lson);
else{
int ans=max(Quary(L,m,lson),Quary(m+1,R,rson));
if(a[Node[rt<<1].R]<a[Node[rt<<1|1].L]) ans=max(ans,min(m-L+1,Node[rt<<1].rsum)+min(R-m,Node[rt<<1|1].lsum));
return ans;
}
}
int main()
{
int T;in(T);
while(T--){
int n,m;
in(n),in(m);
build(1,n,1);
char s[2];
for(int i=0;i!=m;++i)
{
scanf("%s",s);
if(s[0]=='Q'){
int b,c;
in(b),b++;
in(c),c++;
printf("%d\n",Quary(b,c,1,n,1));
}
else{
int b,c;
in(b),b++;in(c);
a[b]=c;
updata(b,1,n,1);
}
}
}
return 0;
}
//错误:建树时混淆了区间长度和左右边界的关系,在查询没有设计好合并这一种情况