• [HEOI2016] 序列


    Description

    有n个数,每个数有若干取值,但是只能在原数列的一个位置变换取值,求一个最长上升子序列,满足无论数列如何变化,这都是一个最长上升子序列。

    Solution

    记录 (l[i],r[i]) 分别表示 (i) 能取到的最大最小值,(val[i]) 为原数列。

    我们来看看满足条件的二元组 (i,j) 满足什么条件。

    1. (i<j)
    2. (val[i]<val[j])
    3. (r[i]<val[j])
    4. (val[i]<l[j])

    观察到条件2包含在条件3,4里。

    二维偏序问题,上CDQ就行。

    Code

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
    #define N 100005
    #define min(A,B) ((A)<(B)?(A):(B))
    #define max(A,B) ((A)>(B)?(A):(B))
    #define swap(A,B) ((A)^=(B)^=(A)^=(B))
    
    int f[N];
    int ans[N];
    int n,m,len;
    int last[N];
    
    struct Node{
        int val,l,r,idx;
    }node[N];
    
    bool cmp(Node x,Node y){
        return x.l<y.l;
    }
    
    bool cmp2(Node x,Node y){
        return x.idx<y.idx;
    }
    
    bool cmp3(Node x,Node y){
        return x.val<y.val;
    }
    
    void add(int x,int y){
        for(;x<=len;x+=x&-x)
            f[x]=max(f[x],y);
    }
    
    int query(int x){
        int now=0;
        for(;x;x-=x&-x)
            now=max(now,f[x]);
        return now;
    }
    
    int getint(){
        int x=0,f=0;char ch=getchar();
        while(!isdigit(ch)) f|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        return f?-x:x;
    }
    
    void cdq(int l,int r){
        if(l>=r) return;
        int mid=l+r>>1;
        cdq(l,mid);
        std::sort(node+l,node+mid+1,cmp3);
        std::sort(node+mid+1,node+r+1,cmp);
        int a=l; memset(f,0,sizeof f);
        for(int j=mid+1;j<=r;j++){
            while(a<=mid and node[a].val<=node[j].l){
                add(node[a].r,ans[node[a].idx]);
                a++;
            }
            int p=query(node[j].val);
            ans[node[j].idx]=max(ans[node[j].idx],p+1);
        }
        std::sort(node+l,node+r+1,cmp2);
        cdq(mid+1,r);
    }
    
    signed main(){
        n=getint(),m=getint();
        for(int i=1;i<=n;i++){
            ans[i]=1;
            node[i].val=node[i].l=node[i].r=getint();
            len=max(len,node[i].l);
            node[i].idx=i;
        }
        for(int i=1;i<=m;i++){
            int x=getint(),y=getint();
            len=max(len,y);
            node[x].r=max(node[x].r,y);
            node[x].l=min(node[x].l,y);
        }
        cdq(1,n);
        int maxn=0;
        for(int i=1;i<=n;i++)
            maxn=max(maxn,ans[i]);
        printf("%d
    ",maxn);
        return 0;
    }
    
  • 相关阅读:
    一个列表如何根据另一个列表进行排序(数组的相对排序)
    汉诺塔问题
    python面向对象基础
    python爬虫
    软件开发目录规范
    python--->包
    编译python文件
    python文件的俩种用途
    python模块的搜索路径
    python 循环导入的问题
  • 原文地址:https://www.cnblogs.com/YoungNeal/p/9374452.html
Copyright © 2020-2023  润新知