题解- CF650D Zip-line
- 题目意思
就是给你个序列以及多次操作,每次把 a i ai ai换做 b i bi bi求一遍 l i s lis lis(操作之间互不影响)
- S o l Sol Sol
显然每次修改暴力做 l i s lis lis是不可行的复杂度至少为 O ( n 2 log n ) O(n^2 \log n ) O(n2logn)。于是我们要思考每次修改会对答案形成怎样的影响。
先对原序列每个点做一遍以他为结束的 l i s lis lis记为 f i fi fi,以他作为起始的 l i s lis lis记为 g i gi gi。易得原序列的 l i s lis lis就为 m a x { f i + g i − 1 } max\{fi+gi-1\} max{fi+gi−1}。
每次对于修改一个值分几种情况来考虑 (思路借鉴 霜雪谦年 的题解),我们记修改过后的 f i fi fi为 f i ′ fi' fi′, g i ′ gi' gi′同理。
对于 + 1 +1 +1的情况如果 f i ′ + g i ′ + 1 > a n s fi'+gi'+1>ans fi′+gi′+1>ans那就更新答案
对于 − 1 -1 −1的情况相对复杂一点。我们要先判断此次修改的点是否为原序列 l i s lis lis的必经之点,判断的方法很简单如果 f i + g i − 1 = a n s fi+gi-1=ans fi+gi−1=ans,并且这样的情况有且只有一种。
剩余的就是不变的情况了。于是我们这道题目就做完了。求 l i s lis lis可以使用树状数组来实现 f i fi fi正着 g i gi gi倒着即可并且要离散化一下就可以了。用离线来实现。
- C o d e Code Code
#include <bits/stdc++.h>
#define lowbit(x) x&(-x)
using namespace std;
const int N=800005;
int n,m,ans,f[N],g[N],tr[N];
int a[N],b[N],res[N],cs[N],cnt;
struct number {
int id,x,val;
int f,g;
inline bool friend operator < (const number &a,const number &b) {
if(a.x==b.x) return a.val<b.val;
return a.x<b.x;
}
};
number q[N];
inline int read() {
int sum=0; char ch=getchar();
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch))
sum=sum*10+(ch^48),ch=getchar();
return sum;
}
inline void jia(int x,int v) {
while(x<=cnt) {
tr[x]=max(tr[x],v);
x+=lowbit(x);
}
}
inline int query(int x) {
int ret=0;
while(x) {
ret=max(ret,tr[x]);
x-=lowbit(x);
}
return ret;
}
int main() {
n=read(),m=read();
cnt=n;
for ( int i=1;i<=n;i++ ) {
a[i]=read();
b[i]=a[i];
}
for ( int i=1;i<=m;i++ ) {
q[i].id=i;
q[i].x=read();
q[i].val=read();
b[++cnt]=q[i].val;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
for ( int i=1;i<=n;i++ ) a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
for ( int i=1;i<=m;i++ ) q[i].val=lower_bound(b+1,b+cnt+1,q[i].val)-b;
for ( int i=1;i<=n;i++ ) {
f[i]=query(a[i]-1)+1;
jia(a[i],f[i]);
}
memset(tr,0,sizeof(tr));
for ( int i=n;i>=1;i-- ) {
g[i]=query(cnt-a[i])+1;
jia(cnt-a[i]+1,g[i]);
}
for ( int i=1;i<=n;i++ ) ans=max(ans,f[i]+g[i]-1);
for ( int i=1;i<=n;i++ ) if(f[i]+g[i]-1==ans) cs[f[i]]++;
sort(q+1,q+m+1);
memset(tr,0,sizeof(tr));
int now=1;
for ( int i=1;i<=m;i++ ) {
while(now<q[i].x) {
jia(a[now],f[now]);
now++;
}
q[i].f=query(q[i].val-1);
}
memset(tr,0,sizeof(tr));
now=n;
for ( int i=m;i>=1;i-- ) {
while(now>q[i].x) {
jia(cnt-a[now]+1,g[now]);
now--;
}
q[i].g=query(cnt-q[i].val);
if(q[i].f+q[i].g+1>ans) res[q[i].id]=q[i].f+q[i].g+1;
}
for ( int i=1;i<=m;i++ ) if(!res[q[i].id]) {
if(f[q[i].x]+g[q[i].x]==ans+1&&cs[f[q[i].x]]==1&&q[i].f+q[i].g+1<ans) res[q[i].id]=ans-1;
else res[q[i].id]=ans;
}
for ( int i=1;i<=m;i++ ) printf("%d\n",res[i]);
}