链接:https://www.nowcoder.com/acm/contest/158/B
来源:牛客网
题目描述
给你一个长度为 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
这道题最开始的时候写的时候是直接暴力,结果超时了。然后看了题解,和大佬的代码才明白其中一种做法。这道题有两种做法。第一种:我们用一个数组b[i]表示从第i个数开始连续上升子序列的长度,c[i]表示长度为i的上升子序列的个数。我们每改变一个数字,就要判断一下a[x],从第x位开始对后面序列长度造成的影响,因为1<=a[i]<=100,上升序列的长度最长只有100位,我们只用判断x+100位后面上升数列的长度的变化。
第一种方法的代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+10;
int cnt[MAXN],a[MAXN], b[MAXN];
int solve(){
for(int i = 100; i >= 1; i--){
if(cnt[i]){
return i;
}
}
return 0;
}
int main(){
int n, m;
while(~scanf("%d %d",&n, &m)){
memset(cnt, 0, sizeof(cnt));
for(int i = 1; i <= n; i++){
scanf("%d",&a[i]);
if(a[i] > a[i-1]) b[i] = b[i-1] + 1;
else b[i] = 1;
cnt[b[i]]++;
}
printf("%d\n",solve());
while(m--){
int x, y;
scanf("%d %d",&x, &y);
a[x] = y;
for(int i = x; i <= min(x+100,n); i++){
int s = 1;
if(a[i] > a[i-1]) s = b[i-1] + 1;
cnt[b[i]]--;
b[i] = s;
cnt[b[i]]++;
}
printf("%d\n",solve());
}
}
return 0;
}
第二种方法是用线段树做,不过这种方法我还没搞懂,先上一份模仿大佬的代码。在这里立一个flag,一周内把它给搞懂,然后将出来。
#include<cstdio>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 2e5+110;
int a[MAXN];
struct SegementTree{
int lm,rm;
int sum;
#define le(x) tree[x].lm
#define ri(x) tree[x].rm
#define sum(x) tree[x].sum
}tree[MAXN << 2];
void push_up(int u, int l, int r){
le(u) = le(2*u);
ri(u) = ri(2*u+1);
sum(u) = max(sum(2*u), sum(2*u+1));
int mid = (l+r) >> 1;
if(a[mid] < a[mid+1]){
if(le(2*u) == mid-l+1) le(u) = le(2*u) + le(2*u+1);
if(ri(2*u+1) == r-mid) ri(u) = ri(2*u) + ri(2*u+1);
int t = ri(2*u) + le(2*u+1);
if(t > sum(u)) sum(u) = t;
}
}
void build(int p,int l, int r){
if(l == r){
le(p) = ri(p) = sum(p) = 1;
return ;
}
int mid = (l+r) >> 1;
build(2*p,l, mid);
build(2*p+1, mid+1, r);
push_up(p,l,r);
}
void change(int u, int l, int r, int p, int d){
if(l == r){
a[l] = d;
return ;
}
int mid = (l+r) >> 1;
if(p <= mid)
change(2*u,l,mid, p, d);
else
change(2*u+1,mid+1,r, p, d);
push_up(u, l, r);
}
int ask(int u, int l, int r, int tl, int tr){
if(tl <= l && r <= tr)
return sum(u);
int mid = (l+r) >> 1;
if(tr <= mid)
return ask(2*u,l,mid,tl,tr);
else if(tl > mid)
return ask(2*u+1,mid+1,r, tl, tr);
else{
int t1 = ask(2*u,l,mid,tl, mid), t2 = ask(2*u+1,mid+1,r, mid+1, tr), t = max(t1,t2);
if(a[mid] < a[mid+1])
t1 = min(ri(2*u), mid-tl+1), t2 = min(le(2*u+1),tr-mid),t1 += t2;
return max(t,t1);
}
}
int main(){
int n, m;
while(~scanf("%d %d",&n,&m)){
for(int i = 1; i <= n; i++)
scanf("%d",&a[i]);
build(1, 1, n);
printf("%d\n",ask(1,1,n,1,n));
while(m--){
int l,r;
scanf("%d %d",&l, &r);
change(1,1,n,l,r);
printf("%d\n", ask(1,1,n,1,n));
}
}
return 0;
}