[二分][LIS]JZOJ 5920 风筝
分析
这个其实挺简单的,我们先看一下有哪些情况,显然只有两种:
1、更改的数不在原最长不下降子序列中,直接输出原LIS(或通过该数产生的新LIS)
2、更改的数在原最长不下降子序列中,这时候要分类讨论:如果有替代的数(即在原LIS中排名相同)则是原序列长,否则原长-1
关于排名大佬们可以采用主席树
像我们这种菜鸡只能离线,排序询问以后求出包括询问及询问之前的LIS和包括询问及询问以后的LIS(正反做一遍nlogn求即可)
然后判断两LIS长之和-1是否为原LIS长,是则在LIS中,顺便用这个维护同排名出现次数
最后要吐槽出题人的是实际数据范围5e5
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=5e5+10; struct Task { int x,y,id,rnkpre,rnknex; }q[N]; int lispre[N],lisnex[N]; int d[N],h[N],belis[N],ans[N]; int n,m,len; bool Cmp(Task a,Task b) { return a.x<b.x; } int main() { freopen("kite.in","r",stdin); freopen("kite.out","w",stdout); scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&h[i]); for (int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].id=i; sort(q+1,q+m+1,Cmp); for (int i=1;i<=n;i++) d[i]=2147483647; int st=1; for (int i=1;i<=n;i++) { for (;st<=m&&q[st].x==i;st++) { int justanumber=lower_bound(d+1,d+n+1,q[st].y)-d; q[st].rnkpre=justanumber; } int justanumber=lower_bound(d+1,d+n+1,h[i])-d; lispre[i]=justanumber;d[justanumber]=h[i]; len=max(len,justanumber); } st=m; for (int i=1;i<=n;i++) d[i]=2147483647; for (int i=n;i;i--) { for (;st&&q[st].x==i;st--) { int justanumber=lower_bound(d+1,d+n+1,-q[st].y)-d; q[st].rnknex=justanumber; } int justanumber=lower_bound(d+1,d+n+1,-h[i])-d; lisnex[i]=justanumber;d[justanumber]=-h[i]; } for (int i=1;i<=n;i++) if (lispre[i]+lisnex[i]-1==len) belis[lispre[i]]++; for (int i=1;i<=m;i++) { if (q[i].rnkpre+q[i].rnknex>len) ans[q[i].id]=q[i].rnkpre+q[i].rnknex-1; else if (lispre[q[i].x]+lisnex[q[i].x]-1==len&&belis[lispre[q[i].x]]==1) ans[q[i].id]=len-1; else ans[q[i].id]=len; } for (int i=1;i<=m;i++) printf("%d\n",ans[i]); }
在日渐沉没的世界里,我发现了你。