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

    这道题是DP应该不难看出来。

    $dp[i]$表示选择$i$以后所能形成的满足条件的子序列的最大值

    转移的时候枚举前面的点$(j)$。

    设$MX[i]$表示$i$号位置能变成的最大值,$MI[i]$表示$i$号位置能变成的最小值,$a$为原序列

    这样转移的时候会有两个限制条件

    $a[i]>=MX[j]$ && $MI[i]>=a[j]$

    这很明显是个二维偏序问题嘛,用CDQ树套树什么的都可以搞。

    树套树的话,将$a$抽象为$x$轴,将$MX$抽象为$y$轴

    转移的时候我们实际是在左下角为$(0,0)$,右上角为$MI[i],a[i]$的矩阵中查最大值

    每次转移对答案的贡献的话实际上只是改变了$a[i],mx[i]$的值

    然后就能很自然的想到树套树了,线段树套线段树或者树状数组套线段树都可以搞

    后者常数小一些

    线段树的数组一定要开的足够大!!!!

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    const int MAXN=6*1e6+10;
    const int MAXNN=1e5+10;
    const int INF=1e8+10;
    inline int read()
    {
        char c=getchar();int x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    int root[MAXN],N,M,MX[MAXNN],MI[MAXNN],a[MAXNN];
    struct S
    {
        struct node
        {
            int ls,rs,mx;
        }T[MAXN];
        int tot;
        int query(int now,int ll,int rr,int pos)
        {
            if(ll==rr) 
                return T[now].mx;
            int mid=ll+rr>>1;
            if(pos<=mid) 
                return query(T[now].ls,ll,mid,pos);
            else 
                return max( T[T[now].ls].mx , query(T[now].rs,mid+1,rr,pos));    
        }
        void change(int &now,int ll,int rr,int pos,int val)
        {
            if(!now) now=++tot;
            T[now].mx=max(T[now].mx,val);
            if(ll==rr) return ;
            int mid=ll+rr>>1;
            if(pos<=mid) change(T[now].ls,ll,mid,pos,val);
            else          change(T[now].rs,mid+1,rr,pos,val);
        }
    }tree;
    struct B
    { 
        int N;
        int Tree[MAXNN];
        int lowbit(int p) {return p&(-p);}
        int Query(int k,int val)
        {
            int ans=0;
            while(k) 
            {
                ans=max(ans,tree.query(root[k],1,N,val));
                k-=lowbit(k);
            }
            return ans;
        }
        void Change(int k,int pos,int val)
        {
            while(k<=N)
            {
                tree.change(root[k],1,N,pos,val);
                k+=lowbit(k);
            }
        }
    }BIT;
    int main()
    {
        //freopen("heoi2016_seq.in","r",stdin);
        //freopen("heoi2016_seq.out","w",stdout);
        N=read();M=read();
        for(int i=1;i<=N;i++) MX[i]=MI[i]=a[i]=read();
        for(int i=1;i<=M;i++)
        {
            int x=read(),y=read();
            MX[x]=max(MX[x],y);BIT.N=max(BIT.N,MX[x]);
            MI[x]=min(MI[x],y);
        }
        int ans=0;
        for(int i=1;i<=N;i++)
        {
            int now=BIT.Query(MI[i],a[i])+1;
            BIT.Change(a[i],MX[i],now);
            ans=max(ans,now);
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:

    类(重要的很)
    异常
    异常
    面向对象oop接口
    面向对象oop多态
    Day10_数组(下)
    Day09_数组(上)
    Day08_网络编程(上)
    Day07_java对象下
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/8439823.html
Copyright © 2011-2022 走看看