HDU-3308线段树+区间合并(好题)

链接:点击打开链接

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<=10 5).
The next line has n integers(0<=val<=10 5).
The next m lines each has an operation:
U A B(0<=A,n , 0<=B=10 5)
OR
Q A B(0<=A<=B< n).
 

Output
For each Q, output the answer.
 

Sample Input
 
 
110 107 7 3 3 5 9 9 8 1 8 Q 6 6U 3 4Q 0 1Q 0 5Q 4 7Q 3 5Q 0 2Q 4 6U 6 10Q 0 9
 

Sample Output
 
 
11423125

单点修改,求区间最长连续上升序列。

这道题关键在于又两个子节点更新父节点以及区间查询的操作。

父节点的最长连续上升序列难道就是两个子节点的最大值吗? 肯定不是,中间那个点肯定会有影响的。

那么我们应该维护区间的三个信息。

区间的最长连续上升序列,tmp【】

区间头为起点的最长连续上升序列  le【】

以区间尾为终点的最长连续上升序列  ri【】

那么更新操作就变成这样的了:

void up(int root,int l,int r)
{
    int mid=l+r>>1;
    if(le[root<<1]==mid-l+1&&a[mid]<a[mid+1]) le[root]=le[root<<1]+le[root<<1|1];
    else le[root]=le[root<<1];
    if(ri[root<<1|1]==r-mid&&a[mid]<a[mid+1]) ri[root]=ri[root<<1]+ri[root<<1|1];
    else ri[root]=ri[root<<1|1];
    tmp[root]=max(tmp[root<<1],tmp[root<<1|1]);
    if(a[mid]<a[mid+1]) tmp[root]=max(tmp[root],ri[root<<1]+le[root<<1|1]);

}

最后就是区间查询的操作了,

定义当前节点为root,区间最左端为nowa,最右端为nowb,需要查询的区间为 L--r。

当 nowa==L nowb==r时 ,直接return tmp【root】;

如果区间全在左儿子中,那么return  root<<1  nowa  (nowa+nowb)/2  L   r

如果区间全在右儿子中,那么return  root<<1|1  1+(nowa+nowb)/2  nowb  L   r

最后就是左右儿子都有。那么先取左右儿子的最大值,在考虑中间的情况。

对于坐儿子,min ( ri[root<<1], (nowa+nowb)/2-L+1 ),这里要说明一下为什么不是直接取ri【root<<1】,因为L不一定能达到nowa的位置,还有就是L是不可能超过nowa的。

同理右儿子也是一样。

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100010;
const ll inf=1e18;
int T,n,m,x,y;
char s[5];
int tmp[maxn<<2],le[maxn<<2],ri[maxn<<2];
int a[maxn];
void up(int root,int l,int r)
{
    int mid=l+r>>1;
    if(le[root<<1]==mid-l+1&&a[mid]<a[mid+1]) le[root]=le[root<<1]+le[root<<1|1];
    else le[root]=le[root<<1];
    if(ri[root<<1|1]==r-mid&&a[mid]<a[mid+1]) ri[root]=ri[root<<1]+ri[root<<1|1];
    else ri[root]=ri[root<<1|1];
    tmp[root]=max(tmp[root<<1],tmp[root<<1|1]);
    if(a[mid]<a[mid+1]) tmp[root]=max(tmp[root],ri[root<<1]+le[root<<1|1]);
}
void build(int root,int l,int r)
{
    if(l==r)
    {
        scanf("%d",&a[l]);
        tmp[root]=le[root]=ri[root]=1;
        return;
    }
    int mid=l+r>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    up(root,l,r);
}
void updata(int root,int l,int r,int pos)
{
    int mid=l+r>>1;
    if(l==r) return;
    if(pos<=mid)  updata(root<<1,l,mid,pos);
    else updata(root<<1|1,mid+1,r,pos);
    up(root,l,r);
}
int query(int root,int nowa,int nowb,int l,int r)
{
    if(l==nowa&&nowb==r) return tmp[root];
    int mid=nowa+nowb>>1;
    if(r<=mid) return query(root<<1,nowa,mid,l,r);
    if(l>mid) return query(root<<1|1,mid+1,nowb,l,r);
    int t1=query(root<<1,nowa,mid,l,mid);   
    int t2=query(root<<1|1,mid+1,nowb,mid+1,r);
    int ans=max(t1,t2);
    if(a[mid]<a[mid+1])
        ans= max(ans,min(ri[root<<1],mid-l+1)+min(le[root<<1|1],r-mid));
    return ans;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        build(1,0,n-1);
        while(m--)
        {
            scanf("%s%d%d",s,&x,&y);
            if(s[0]=='Q') printf("%d\n",query(1,0,n-1,x,y));
            else
            {
                a[x]=y;
                updata(1,0,n-1,x);
            }
        }
    }
    return 0;
}

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值