LCIS HDU 3308
题意:
给出一个长度为N(N <= 100000)的数列,然后是两种操作:
U A B: 将第A个数替换为B (下标从零开始)
Q A B: 输出区间[A, B]的最长连续递增子序列
注意:操作的数目m <= 100000。
解法:
线段树
思路:
|线段树成段更新。每个线段树的结点要求保存的信息有以下几个:
int lMax; // 包含结点左端点的最长连续递增子序列的长度
int rMax; // 包含结点右端点的最长连续递增子序列的长度
int Max; // 当前结点的最长连续递增子序列的长度
int lVal, rVal; // 当前结点管辖的区间左右端点的数值
int l, r; // 当前结点管辖的区间
我们用以下函数从左右儿子中得到当前结点的信息:
void UpdateBy(Tree* ls, Tree* rs);
之所以把它写成函数是因为这里的处理比较麻烦,很容易出错,并且需要
调用多次,这个函数的作用就是通过左右儿子的信息填充本身的信息。
lVal、rVal、l、r等信息比较容易求得。
lMax和rMax的值就比较麻烦了,需要分情况讨论(下面的len表示区间长度):
1. 左儿子最右边的值 < 右儿子最左边的值
lMax = (左儿子的lMax == 左儿子的len) ? 左儿子的len + 右儿子的lMax : 左儿子的lMax;
rMax = (右儿子的rMax == 右儿子的len) ? 右儿子的len + 左儿子的rMax : 右儿子的rMax;
Max = MAX(左儿子的rMax + 右儿子的lMax, 左儿子的Max, 右儿子的Max, lMax, rMax);
2. 左儿子最右边的值 >= 右儿子最左边的值
lMax = 左儿子的lMax;
rMax = 右儿子的rMax;
Max = MAX(左儿子的Max, 右儿子的Max);
AC代码:
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <algorithm> 4 #include <iostream> 5 #define lson l,m,rt<<1 6 #define rson m+1,r,rt<<1|1 7 #define maxn 100005 8 using namespace std; 9 10 int mlen[maxn<<2];//区间最大连续子序列 11 int lmlen[maxn<<2];//以区间左边第一个元素开头的最大连续子序列 12 int rmlen[maxn<<2];//以区间右边最后一个元素结尾的最大连续子序列 13 int num[maxn]; 14 15 void pushup(int rt,int l,int r) 16 { 17 lmlen[rt]=lmlen[rt<<1]; 18 rmlen[rt]=rmlen[rt<<1|1]; 19 mlen[rt]=max(mlen[rt<<1],mlen[rt<<1|1]); 20 int mid=(l+r)>>1; 21 int m=(r-l)+1; 22 if(num[mid]<num[mid+1]) //左区间的右值小于右区间的左值可以合并 23 { 24 if(lmlen[rt]==m-(m>>1)) lmlen[rt]+=lmlen[rt<<1|1]; 25 if(rmlen[rt]==(m>>1)) rmlen[rt]+=rmlen[rt<<1]; 26 mlen[rt]=max(mlen[rt],lmlen[rt<<1|1]+rmlen[rt<<1]); 27 } 28 } 29 void build(int l,int r,int rt) 30 { 31 if(l==r) 32 { 33 mlen[rt]=lmlen[rt]=rmlen[rt]=1; 34 return ; 35 } 36 int m=(l+r)>>1; 37 build(lson); 38 build(rson); 39 pushup(rt,l,r); 40 } 41 void update(int a,int l,int r,int rt) 42 { 43 if(l==r) 44 { 45 return; 46 } 47 int m=(l+r)>>1; 48 if(a<=m) update(a,lson); 49 else update(a,rson); 50 pushup(rt,l,r); 51 } 52 53 int query(int L,int R,int l,int r,int rt) 54 { 55 if(L<=l&&r<=R) 56 { 57 return mlen[rt]; 58 } 59 int m=(l+r)>>1; 60 if(R<=m) return query(L,R,lson); //与一般不同,不能是子集,只能全部属于才能直接查询子区间 返回子区间的mlen 61 if(L>m) return query(L,R,rson); //否则是确认儿子区间是否能合并,并在三者之间取最大值 62 63 int ta,tb; 64 ta=query(L,R,lson); 65 tb=query(L,R,rson); 66 int ans; 67 ans=max(ta,tb); 68 if(num[m]<num[m+1]) //同上 69 { 70 int temp; 71 temp=min(rmlen[rt<<1],m-L+1)+min(lmlen[rt<<1|1],R-m); 72 ans=max(temp,ans); 73 } 74 return ans; 75 } 76 77 int main() 78 { 79 int T,n,m; 80 int i,j; 81 char f[2]; 82 int a,b; 83 scanf("%d",&T); 84 for(i=0;i<T;i++) 85 { 86 scanf("%d %d",&n,&m); 87 for(j=1;j<=n;j++) 88 scanf("%d",&num[j]); 89 build(1,n,1); 90 while(m--) 91 { 92 scanf("%s",&f); 93 if(f[0]=='U') 94 { 95 scanf("%d %d",&a,&b); 96 a++; 97 num[a]=b; 98 update(a,1,n,1); 99 } 100 else 101 { 102 scanf("%d %d",&a,&b); 103 a++,b++; 104 printf("%d\n",query(a,b,1,n,1)); 105 } 106 } 107 } 108 return 0; 109 }
posted on 2012-11-09 00:07 Acmer_Roney 阅读(237) 评论(0) 编辑 收藏 举报