[Tjoi2016&Heoi2016]序列

来源:互联网 发布:淘宝服务中心首页 编辑:程序博客网 时间:2024/06/07 21:16

Description

佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?请你告诉她这个子序列的最长长度即可
。注意:每种变化最多只有一个值发生变化。在样例输入1中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 31 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列在样例输入2中,所有的变化是:3 3 33 2 3选择子序列
为第一个元素和第三个元素,或者第二个元素和第三个元素,均可满足要求

Input

输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。接下来一行有n个数,表示这个数列原始的状态。接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。1 <= x <= n。所有数字均为正整数,且小于等于100,000

Output

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

Sample Input

3 4
1 2 3
1 2
2 3
2 1
3 4

Sample Output

3

分析

设f[i]表示以i为最后一位,能求出的序列最长为多少。
f[i]=max{f[j]+1} 一个可以转移的j要满足以下条件:
1. j< i
2. a[j]< a[i] (两个都不变化)
3. a[j]< Min[i] (i变化,Min[i]为i可变化的最小值)
4. Max[j]< a[i] (j变化,Max[j]为j可变化的最大值)
时间复杂度O(n2)

正解1

其实可以把条件2、3、4合并一下,然后变成max(a[j],Max[j])< a[i] 和a[j]< min(a[i],Min[i])两个条件

两个条件,很容易让人想到用树套树做。
时间复杂度O(nlog2n)

正解2

也是上面的两个条件。
枚举更新f[i]时,可以把它拆成两个操作:查询最大值和插入操作。
操作是相互独立的,而且可以离线做,所以可以考虑cdq分治
对于操作区间[l,r],先处理完[l,mid],然后用这部分的答案更新[mid+1,r]的答案,最后递归处理[mid+1,r]。离线更新答案可以按一个条件排序,然后用树状数组查询。
时间复杂度O(nlog2n)

cdq分治的代码#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn=200005,N=100000;int n,m,tot,a[maxn],b[maxn],c[maxn],f[maxn],s[maxn];struct data{    int x,y,v;}A[maxn],B[maxn];bool cmp(data a,data b){    return a.x<b.x;}int lowbit(int x){    return x & (-x);}void insert(int x,int y){    for (;x<=N;x+=lowbit(x)) s[x]=max(s[x],y);}int get(int x){    int k=0;    for (;x;x-=lowbit(x)) k=max(k,s[x]);    return k;}void clear(int x){    for (;x<=N;x+=lowbit(x)) s[x]=0;}void solve(int l,int r){    if (l==r)    {        f[l]=max(f[l],1);        return;    }    int mid=(l+r)/2,i,j;    solve(l,mid);    for (i=l;i<=mid;i++)    {        A[i].v=f[i];        A[i].x=a[i];        A[i].y=c[i];    }    for (i=mid+1;i<=r;i++)    {        B[i].v=i;        B[i].x=b[i];        B[i].y=a[i];    }    sort(A+l,A+mid+1,cmp);    sort(B+mid+1,B+r+1,cmp);    for (i=l,j=mid+1;j<=r;j++)    {        for (;i<=mid && A[i].x<=B[j].x;i++) insert(A[i].y,A[i].v);        f[B[j].v]=max(f[B[j].v],get(B[j].y)+1);    }    for (i--;i>=l;i--) clear(A[i].y);    solve(mid+1,r);}int main(){    scanf("%d%d",&n,&m);    memset(b,42,sizeof(b));    for (int i=1;i<=n;i++) scanf("%d",&a[i]);    while (m--)    {        int x,y;        scanf("%d%d",&x,&y);        b[x]=min(b[x],y);        c[x]=max(c[x],y);    }    for (int i=1;i<=n;i++)    {        b[i]=min(b[i],a[i]);        c[i]=max(c[i],a[i]);    }    solve(1,n);    int ans=0;    for (int i=1;i<=n;i++) ans=max(ans,f[i]);    printf("%d\n",ans);    return 0;}
0 0
原创粉丝点击