链接:https://www.nowcoder.com/acm/contest/158/B
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给你一个长度为 n 的序列 a ,求最长的连续的严格上升区间的长度。
同时会进行 m 次修改,给定 x , y ,表示将 ax 修改为 y ,每次修改之后都要求输出答案。
输入描述:
第一行 2 个数 n,m,表示序列长度,修改次数; 接下来一行 n 个数表示 ; 接下来 m 行,每行 2 个数 x , y ,描述一次修改。
输出描述:
第一行 1 个数表示最初的答案; 接下来 m 行,第 i 行 1 个数表示第 i 次修改后的答案。
示例1
输入
复制
4 3 1 2 3 4 3 1 2 5 3 7
输出
复制
4 2 2 3
说明
序列变换如下: 1 2 3 4 1 2 1 4 1 5 1 4 1 5 7 4
备注:
n,m ≤ 100000,1 ≤ x ≤ n,1 ≤ ai,y ≤ 100
大致思路:
用线段树来维护最长区间。其实用的是分治思想。我们来考虑这样一个情况。如何寻找区间[l,r]的最长连续区间?
其实很简单,只有三种可能:
1、完全位于[l,mid]区间中;
2、完全位于[mid+1,r]区间内;
3、跨立这个两个区间(其中a[mid]一定小于a[mid+1]才有可能)
我们采用分治的思想,很容易求出前两种情况的最优解。对于第三种情况,一定是[l,mid]包含mid的最长区间加上[mid+1,r]包含mid+1的最长区间。
为了使问题层次更加清晰,我们每个节点用Llen表示包含l的最长区间,Rlen表示包含r的最长区间,maxlen表示最长区间。
那么,我们可以建立如下递推式:
tree[k].maxlen = max ( tree[k<<1].maxlen , tree[k<<1|1].maxlen , tree[k<<1].Rlen + tree[k<<1|1].Llen );
其中不止是maxlen需要更新,Rlen和Llen也需要更新;
tree[k<<1].Llen 其中a[mid]>=a[mid+1]
tree[k].Llen=
tree[k<<1].Llen+tree[k<<1|1].Llen 其中a[mid]<a[mid+1]且tree[k<<1].Llen对于该节点的区间长度
tree[k<<1|1].Rlen 其中a[mid]>=a[mid+1]
tree[k].Rlen=
tree[k<<1|1].Rlen+tree[k<<1].Rlen 其中a[mid]<a[mid+1]且tree[k<<1].Rlen对于该节点的区间长度
附上ac代码
# include <iostream>
# include <cstring>
# include <cstdio>
# define L(x) (x<<1)
# define R(x) (x<<1|1)
using namespace std;
const int MAXN = 1e5+10;
struct node
{
int l,r,maxlen;
int Llen,Rlen;
int mid(){
return (l+r)>>1;
}
int len(){
return r-l+1;
}
};
node tree[MAXN<<2];
int a[MAXN];
void pushup(int k)
{
tree[k].Llen=tree[L(k)].Llen;
tree[k].Rlen=tree[R(k)].Rlen;
tree[k].maxlen=max(tree[L(k)].maxlen,tree[R(k)].maxlen);
int mid = tree[k].mid();
if(a[mid]<a[mid+1])
{
if(tree[L(k)].Llen==tree[L(k)].len())
tree[k].Llen+=tree[R(k)].Llen;
if(tree[R(k)].Rlen==tree[R(k)].len())
tree[k].Rlen+=tree[L(k)].Rlen;
tree[k].maxlen=max(tree[k].maxlen,tree[L(k)].Rlen+tree[R(k)].Llen);
}
return ;
}
void build(int l,int r,int k)
{
tree[k].l=l;
tree[k].r=r;
if(l==r)
{
tree[k].maxlen=tree[k].Llen=tree[k].Rlen=1;
return ;
}
int mid = tree[k].mid();
build(l,mid,L(k));
build(mid+1,r,R(k));
pushup(k);
return ;
}
void updata(int pos, int k)
{
if(tree[k].len()==1)
return ;
int mid=tree[k].mid();
if(pos<=mid)
updata(pos,L(k));
else
updata(pos,R(k));
pushup(k);
return ;
}
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
memset(tree,0,sizeof tree);
build(1,n,1);
printf("%d\n",tree[1].maxlen);
while(m--)
{
int pos,v;
scanf("%d%d",&pos,&v);
a[pos]=v;
updata(pos,1);
printf("%d\n",tree[1].maxlen);
}
return 0;
}