• 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
    ",Ans[i]);
        return 0;
    }
    
    
  • 相关阅读:
    结队-贪吃蛇游戏-项目进度
    团队-象棋游戏-开发环境搭建过程
    团队-中国象棋游戏-设计文档
    结对-贪吃蛇游戏-开发环境搭建过程
    结对-结对编项目贪吃蛇-设计文档
    课后作业-阅读任务-阅读提问-1
    《20170911-构建之法:现代软件工程-阅读笔记》
    团队-中国象棋-成员简介及分工
    团队-团队编程项目中国象棋-需求分析
    结队-结队编程项目贪吃蛇--需求分析
  • 原文地址:https://www.cnblogs.com/wmq12138/p/11740738.html
Copyright © 2020-2023  润新知