最近开始线段树一段时间了,也发现了不少大牛的博客比如HH大牛 ,小媛姐。这个题目是我在看HH大牛的线段树专题是给出的习题,(可以去他博客找找,真心推荐)原本例题是POJ3667 Hotel 这个题目,是一个求连续空区间的情况,而hdoj这个题目是求给定区间单调连续的最大区间长度,两个题目思路很相似,将节点rt用sum[rt],lsum[rt],rsum[rt]来描述,分别表示rt对应区间即[l,r]内满足条件的区间的最大长度,从左边端点l开始满足条件的最大区间长度,从右边r开始向左的满足条件的最大区间长度。
void PushUp(int rt,int m,int mid)//mid表示更新区间的中点,m表示长度
{
lsum[rt]=lsum[rt<<1];
rsum[rt]=rsum[rt<<1|1];
int t=1;
if(A[mid]<A[mid+1])
{
if(lsum[rt]==(m-(m>>1)))
lsum[rt]+=lsum[rt<<1|1];
if(rsum[rt]==(m>>1))
rsum[rt]+=rsum[rt<<1];
t= rsum[rt<<1]+lsum[rt<<1|1];
}
sum[rt]=max(t,max(sum[rt<<1],sum[rt<<1|1]));
}
PushUp函数和query函数是关键 ,PushUp函数向上更新时,先将lsum[rt]用
lsum[rt<<1]也就是左子区间左边开始的最大长度,如果这个区间长度刚好是l到mid之间的长度,说明区间已经穿过中点了,应该在加上右子区间lsum[rt<<1|1]这部分,类似的可以更新rsum[rt]。对于sum[rt]应该对应rsum[rt<<1]+lsum[rt<<1|1],sum[rt<<1],sum[rt<<1|1]三种情况中的最大值,因为满足条件的最长单调区间可以是左半部分,右半部分,或者贯穿中点。
理解了这部分那么query函数可以按照类似的思路来写,但要注意的是对于贯穿中点的判断条件是A[mid]<A[mid+1],这样才能将两部分加起来。
期间又一次犯二TLE了,原本是用C写的,max函数是用的宏定义,结果里面含有query函数,这样最终可能会两次调用query函数,不超时才怪,好在以前犯过一次,被基友发现了,改成algorithm里面的max就过了。哎,有个能debug基友就是好啊。hhha。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define N 100010 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 8 using namespace std; 9 int sum[N<<2],rsum[N<<2],lsum[N<<2],A[N]; 10 11 void PushUp(int rt,int m,int mid) 12 { 13 lsum[rt]=lsum[rt<<1]; 14 rsum[rt]=rsum[rt<<1|1]; 15 int t=1; 16 if(A[mid]<A[mid+1]) 17 { 18 if(lsum[rt]==(m-(m>>1))) 19 lsum[rt]+=lsum[rt<<1|1]; 20 if(rsum[rt]==(m>>1)) 21 rsum[rt]+=rsum[rt<<1]; 22 t= rsum[rt<<1]+lsum[rt<<1|1]; 23 } 24 sum[rt]=max(t,max(sum[rt<<1],sum[rt<<1|1])); 25 } 26 27 void build(int l,int r,int rt) 28 { 29 if(l==r) 30 { 31 sum[rt]=lsum[rt]=rsum[rt]=1; 32 return; 33 } 34 int m=(l+r)>>1; 35 build(lson); 36 build(rson); 37 PushUp(rt,r-l+1,m); 38 } 39 40 void update(int p,int l,int r,int rt) 41 { 42 if(l==r) 43 return; 44 int m=(l+r)>>1; 45 if(p<=m) 46 update(p,lson); 47 else update(p,rson); 48 PushUp(rt,r-l+1,m); 49 } 50 51 int query(int L,int R,int l,int r,int rt) 52 { 53 if(L<=l&&R>=r) 54 { 55 return sum[rt]; 56 } 57 int m=(l+r)>>1; 58 if(l==r) 59 return 1; 60 int ans=0; 61 if(R<=m) 62 ans=max(ans,query(L,R,lson)); 63 else if(L>m) 64 ans=max(ans,query(L,R,rson)); 65 else 66 { 67 ans=max(ans,query(L,R,lson)); 68 ans=max(ans,query(L,R,rson)); 69 int ll,rr; 70 if(m-L+1>=rsum[rt<<1]) 71 ll=rsum[rt<<1]; 72 else ll=m-L+1; 73 if(R-m>=lsum[rt<<1|1]) 74 rr=lsum[rt<<1|1]; 75 else rr=R-m; 76 ans=max(ans,ll); 77 ans=max(ans,rr); 78 if(A[m+1]>A[m]) 79 ans=max(ans,ll+rr); 80 } 81 return ans; 82 } 83 84 int main(void) 85 { 86 int T; 87 int n,m,a,b; 88 char op[3]; 89 scanf("%d",&T); 90 while(T--) 91 { 92 scanf("%d%d",&n,&m); 93 for(int i=1; i<=n; i++) 94 scanf("%d",A+i); 95 build(1,n,1); 96 while(m--) 97 { 98 scanf("%s%d%d",op,&a,&b); 99 if(op[0]=='U') 100 { 101 A[a+1]=b; 102 update(a+1,1,n,1); 103 } 104 else 105 { 106 int ans=query(a+1,b+1,1,n,1); 107 printf("%d\n",ans); 108 } 109 } 110 } 111 return 0; 112 }