链接: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
输出 【牛客网 练习赛25 B最长区间】复制
4 2 2 3
说明
序列变换如下: 1234 1214 1514 1574
备注:
n,m ≤ 100000,1 ≤ x ≤ n,1 ≤ ai,y ≤ 100
解法1:
线段树维护区间最长严格递增子序列
#include
#define lson l,mid,(rt<<1)
#define rson (mid+1),r,(rt<<1|1)
using namespace std;
const int MAXN = 100005;
struct node{
int l,r;
// 当前节点区间左右端点
int lsum,rsum,msum;
// 当前节点 左侧部分LICS 、 右侧 LCIS 、 总的最大的LCIS
int mid(){
return (l+r) >> 1;
}
};
node tree[MAXN << 2];
int num[MAXN];
void pushUp(int rt){
// 初始为 左右孩子 中最大的 msum
tree[rt].msum = max(tree[rt<<1].msum,tree[rt<<1|1].msum);
tree[rt].lsum = tree[rt<<1].lsum;
// 初始为 对应的 LCIS (lsum 对应左孩子的LCIS、右孩子 对应右侧LCIS)
tree[rt].rsum = tree[rt<<1|1].rsum;
// 如果 左儿子最右侧值 小于 右儿子 最左侧值 则 更新 父节点的 lsum,rsum,msum
if(num[tree[rt<<1].r] < num[tree[rt<<1|1].l]){
int mid = tree[rt].mid();
if(tree[rt<<1].lsum == mid-tree[rt].l + 1){ // lsum 的LCIS 长度等于其对应区间长度 说明 该区间整体严格递增(更新:加上右侧递增部分长度)
tree[rt].lsum += tree[rt<<1|1].lsum;
}
if(tree[rt<<1|1].rsum == tree[rt].r-mid){//同上
tree[rt].rsum += tree[rt<<1].rsum;
}
tree[rt].msum = max(tree[rt].msum,tree[rt<<1].rsum + tree[rt<<1|1].lsum);
}
}void build(int l, int r, int rt){
tree[rt].l = l;
tree[rt].r = r;
if(l == r){
tree[rt].lsum = tree[rt].rsum = tree[rt].msum = 1;
return;
}
int mid = (l+r) >> 1;
build(lson);
build(rson);
pushUp(rt);
}void update(int a, int b, int rt){
if(tree[rt].l == tree[rt].r){
num[a] = b;
return;
}
int mid = tree[rt].mid();
if(a <= mid)
update(a,b,rt<<1);
else
update(a,b,rt<<1|1);
pushUp(rt);
}int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m,t;
cin >> n >> m;
for(int i = 1;
i <= n;
++i){
cin >> num[i];
}
build(1,n,1);
cout << tree[1].msum << endl;
int a,b;
while(m--){
cin >> a >> b;
update(a,b,1);
cout << tree[1].msum << endl;
}return 0;
}
解法2:
每次只影响改变位置之后的位置,注意题目最长序列为100,依据此可以进行优化。
#include
#include
#include
#include
推荐阅读
- 线段树|[类欧几里得算法 线段树] BZOJ 1938 [CROATIAN2010] ALADIN
- 牛客 C. 子段乘积(线段树)
- 牛客挑战赛39 C 牛牛的等差数列(线段树)(*)
- 牛客 数据结构(区间修改+求区间元素平方和)
- 校门外的树 线段树版
- 树链剖分|牛客练习赛51 F-ABCBA(树链剖分,线段树,状态转移)
- 数论|bzoj 1938 - 类欧几里得+线段树
- 线段树|FZU - 2277(树链剖分或dfs序+线段树)
- 并查集|[CF938G] Shortest Path Queries