题目传送门:CF650D Zip-line
更好的阅读体验
题目大意:给一个序列(a),多次询问(独立),问把(a_x) 变为 (y) 后序列的(LIS)
首先发现答案只可能+(1),-(1),不变
先用树状数组求出来原序列的(LIS),设(f_i)表示以(a_i)为结尾的(LIS),(g_i)表示以(a_i)为开头的(LIS)
(1.) +(1)的情况:由于只改变了(a_i),所以只要看经过i的LIS即可:
设(f')为满足(j<i,a_j<a_i')的最大(f_j),(g')为满足 (j>i,a_j>a_i)的最大(g_j)
若(f'+g'+1>)原(LIS),则(Ans=f'+g'+1)
(2.) -(1)的情况:首先(i)一定是关键点,即是(LIS)的必经之路,然后判断一下(f'+g'+1)是否小于原(LIS)
判断关键点:
对于(f_i+g[i]=ans)的点 记其 (f_i) 出现次数+1
一个点是关键点:当且仅当 (f_i+g_i-1 = Ans) 且 这样的(f_i)只出现过一次
求(f_i) 和 (g_i) 的过程不用说,裸的树状数组求(LIS)
求(f') :将询问离线,按x从小到大排序
求(g') :倒过来再扫一次即可
#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define rint register int
#define il inline
#define For(i,j,k) for(register int i=(j);i<=(k);++i)
#define Rep(i,j,k) for(register int i=(j);i>=(k);--i)
il int read(int x=0,int g=1,char ch='0')
{
while(!isdigit(ch=getchar())) if(ch=='-') g=-1;
while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return g*x;
}
const int N=8e5+5;
int a[N],b[N],g[N],f[N],c[N],cnt[N];
//g[i]:以第i个为开头,f[i]:以第i个为结尾的上升子序列长度
int n,m,ans,tmp,Ans[N];
struct node {int a,b,id,g,f;}q[N];
bool operator <(const node &n1,const node &n2) { return n1.a==n2.a?n1.b<n2.b:n1.a<n2.a; }
il void add(int x,int d) { for(;x<=tmp;x+=x&-x) c[x]=max(c[x],d); }
il int query(int x) { int ret=0; for(;x;x-=x&-x) ret=max(ret,c[x]); return ret; }
il void cls(int *c) { For(i,0,tmp) c[i]=0; }
il void work()
{
sort(q+1,q+m+1);
int t=1; cls(c);
For(i,1,m)
{
while(t<q[i].a) add(a[t],f[t]),++t;
q[i].f=query(q[i].b-1);
}
t=n; cls(c);
Rep(i,m,1)
{
while(t>q[i].a) add(tmp-a[t]+1,g[t]),--t;
q[i].g=query(tmp-q[i].b);
if(q[i].g+q[i].f+1>ans) Ans[q[i].id]=q[i].g+q[i].f+1;
}
For(i,1,m) if(!Ans[q[i].id])
{
if(f[q[i].a]+g[q[i].a]-1==ans&&cnt[f[q[i].a]]==1&&q[i].g+q[i].f+1<ans)
Ans[q[i].id]=ans-1;
else Ans[q[i].id]=ans;
}
}
int main()
{
tmp=n=read(); m=read();
For(i,1,n) b[i]=a[i]=read();
For(i,1,m) q[i].a=read(),q[i].b=read(),q[i].id=i,b[++tmp]=q[i].b;
sort(b+1,b+tmp+1); tmp=unique(b+1,b+tmp+1)-b-1;
For(i,1,n) a[i]=lower_bound(b+1,b+tmp+1,a[i])-b;
For(i,1,m) q[i].b=lower_bound(b+1,b+tmp+1,q[i].b)-b;//离散化
++tmp;
For(i,1,n) f[i]=query(a[i]-1)+1,add(a[i],f[i]); cls(c);
Rep(i,n,1) g[i]=query(tmp-a[i])+1,add(tmp-a[i]+1,g[i]);
For(i,1,n) ans=max(ans,f[i]+g[i]-1);
For(i,1,n) if(f[i]+g[i]-1==ans) ++cnt[f[i]];
work();
For(i,1,m) printf("%d
",Ans[i]);
return 0;
}