CF650D Zip-line 题解
题目传送门: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\n",Ans[i]);
return 0;
}