zoukankan      html  css  js  c++  java
  • 洛谷 P4093 [HEOI2016/TJOI2016]序列

    题目描述

    佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可 。

    注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:

    1 2 3
    2 2 3
    1 3 3
    1 1 3
    1 2 4
    选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:

    3 3 3
    3 2 3
    选择子序列为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要

    输入输出格式

    输入格式:
    输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。

    输出格式:
    输出一个整数,表示对应的答案

    输入输出样例

    输入样例#1:
    3 4
    1 2 3
    1 2
    2 3
    2 1
    3 4
    输出样例#1:
    3
    说明

    对于20%数据所有数字均为正整数,且小于等于300

    对于50%数据所有数字均为正整数,且小于等于3,000

    对于100%数据所有数字均为正整数,且小于等于100,000


    我们设(maxv_i)为第(i)个数变化的最大值;(minv_i)为第(i)个数变化的最小值,(a_i)位原来的数值

    则题目要求转化为,求一个最长的序列,使一下条件满足

    • (j<i)
    • (max(a_j,maxv_j) le a_i)
    • (a_jle min(a_i,minv_i))

    那这种不等式问题就能转化为二维数点问题

    对于每一个j,我们每一次就可以在平面内加一个坐标为((maxv_j,a_j))的权值为(dp_j)点,对于每一次转移,可以从((0,0))((a_i,minv_i))中找到一个点权最大的点,当前点答案就是找到点的权值+1。

    找点就能用很多数据结构维护,cdq分制树套树,k-d tree都可以,这里我用了树状数组套treap,相比于套动态开点线段树,平衡树比线段树空间更小,空间复杂度(O(nlogn))

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<queue>
    #include<bitset>
    using namespace std;
    const int maxn=150000+23333;
    typedef long long ll;
    inline int read(){
        int an=0,f=1;
        char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch<='9'&&ch>='0'){an=an*10+(ch^48);ch=getchar();}
        return an*f;
    }
    /*
    j<i
    a_j<a_i
    a_j<min_{a_i}
    max_{a_j}<a_i
    f_i=max(f_i,f_j+1)
    */
    int n,m;
    int a[maxn],b[maxn],c[maxn],maxv;
    int dp[maxn];
    struct Treap{
        int ran[maxn<<3],l[maxn<<3],r[maxn<<3],v[maxn<<3],w[maxn<<3],cnt,ma[maxn<<3];
        inline void update(int k){ma[k]=max(ma[r[k]],max(w[k],ma[l[k]]));}
        inline void l_change(int &k){int t=r[k];r[k]=l[t];l[t]=k;update(k);update(t);k=t;}
        inline void r_change(int &k){int t=l[k];l[k]=r[t];r[t]=k;update(k);update(t);k=t;}
        inline void insert(int &k,int x,int val){
            if(!k){cnt++;k=cnt;ran[k]=rand();ma[k]=w[k]=val;v[k]=x;return;}
            else if(v[k]==x)w[k]=max(w[k],val);
            else if(x<v[k]){insert(l[k],x,val);if(ran[l[k]]<ran[k])r_change(k);}
            else {insert(r[k],x,val);if(ran[r[k]]<ran[k])l_change(k);}
            update(k);
        }
        inline int query(int k,int x){
            int re=0;
            for(;k;){
                if(v[k]>x)k=l[k];
                else re=max(re,max(ma[l[k]],w[k])),k=r[k];
            }
            return re;
        }\前驱最大
    }t;
    struct BIT{
        int root[maxn];
        inline int query(int k,int x){
            int re=0;
            for(;k;k-=k&-k)
            re=max(re,t.query(root[k],x));
            return re;
        }
        inline void add(int k,int x,int val){
            for(;k<=maxv;k+=k&-k)t.insert(root[k],x,val);
        }
    }T;
    int ans;
    int main(){
        srand(233333);
        n=read();m=read();
        for(int i=1;i<=n;i++)b[i]=c[i]=a[i]=read();
        for(int i=1;i<=m;i++){
            int x=read(),y=read();
            b[x]=min(b[x],y);c[x]=max(c[x],y);
        }
        for(int i=1;i<=n;i++)maxv=max(maxv,c[i]);
        for(int i=1;i<=n;i++){
            int x=T.query(b[i],a[i]);
            dp[i]=x+1;
            T.add(a[i],c[i],dp[i]);
            ans=max(ans,dp[i]);
        }
        cout<<ans;
        return 0;
    }
    

    树套树就是一中思想,具体实现要靠自己领悟


  • 相关阅读:
    pat 甲级 1065. A+B and C (64bit) (20)
    pat 甲级 1064. Complete Binary Search Tree (30)
    pat 甲级 1010. Radix (25)
    pat 甲级 1009. Product of Polynomials (25)
    pat 甲级 1056. Mice and Rice (25)
    pat 甲级 1078. Hashing (25)
    pat 甲级 1080. Graduate Admission (30)
    pat 甲级 团体天梯 L3-004. 肿瘤诊断
    pat 甲级 1099. Build A Binary Search Tree (30)
    Codeforce 672B. Different is Good
  • 原文地址:https://www.cnblogs.com/ck666/p/8442980.html
Copyright © 2011-2022 走看看