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编辑  收藏  举报

导航