版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Tianweidadada/article/details/82079494
链接: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
解法1:
线段树维护区间最长严格递增子序列
#include<bits/stdc++.h>
#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<iostream>
#include<stdio.h>
#include<vector>
#include<map>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<set>
#include<cmath>
using namespace std;
const int N = 100005;
int dp[N];
int sum[N];
int a[N];
int solve(){
for(int i = N; i > 0; --i){
if(sum[i] > 0)
return i;
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n,m;
memset(sum,0,sizeof(sum));
cin >> n >> m;
fill(dp,dp+N,1);
for(int i = 1; i <= n; ++i){
cin >> a[i];
}
for(int i = 2; i <= n; ++i){
if(a[i-1] < a[i]){
dp[i] = max(dp[i],dp[i-1]+1);
}
++sum[dp[i]];
}
// int ans = *max_element(dp+1,dp+n+1);
int ans = solve();
cout << ans <<endl;
int x,v;
while(m--){
cin >> x >> v;
--sum[dp[x]];
a[x] = v;
if(x > 1){
if(a[x-1] < a[x]){
dp[x] = dp[x-1] + 1;
}
else{
dp[x] = 1;
}
}
else{
dp[x] = 1;
}
++sum[dp[x]];
for(int i = x+1; i <= n; ++i){
--sum[dp[i]];
if(a[i-1] < a[i]){
dp[i] = dp[i-1] + 1;
}
else{
dp[i] = 1;
}
++sum[dp[i]];
}
// int ans = *max_element(dp+1,dp+n+1);
int ans = solve();
cout << ans <<endl;
}
return 0;
}