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;
}

posted @ 2019-10-25 20:34  孑行  阅读(254)  评论(0编辑  收藏  举报