【bzoj4553】[Tjoi2016&Heoi2016]序列

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

题解
cdq分治

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define N 100005
struct node{ int v,l,r,id,f;}a[N];
int c[N],n,m;
const int mxn=100000;
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();
    while (ch<'0'||ch>'9') ch=getchar();
    while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}
bool cmp(node a,node b){return a.id<b.id;}
void add(int x,int d) { for (;x<=mxn;x+=x&(-x)) c[x]=max(c[x],d); }
void clear(int x) { for (;x<=mxn;x+=x&(-x)) c[x]=0;}
int query(int x){int ans=0;for (;x;x-=x&(-x)) ans=max(ans,c[x]);return ans;}
void cdq(int n,int l,int r)
{
    if (n<1) return;
    int mid=(l+r)>>1,cnt=0;
    if (l!=r)
    {
        for (int i=1;i<=n;i++)
            if (a[i].v>=l&&a[i].v<=mid||a[i].l>=l&&a[i].l<=mid) swap(a[i],a[++cnt]);
        cdq(cnt,l,mid);
    }
    sort(a+1,a+n+1,cmp);
    for (int i=1;i<=n;i++)
    {
        if (a[i].l>=mid) a[i].f=max(a[i].f,query(a[i].v)+1);
        if (a[i].v<=mid) add(a[i].r,a[i].f);
    }
    for (int i=1;i<=n;i++) clear(a[i].r);
    cnt=0;
    if (l!=r)
    {
        for (int i=1;i<=n;i++)
            if (a[i].v>mid&&a[i].v<=r||a[i].r>mid&&a[i].r<=r) swap(a[i],a[++cnt]);
        cdq(cnt,mid+1,r);
    }
}
int main()
{
    n=read();m=read();
    for (int i=1;i<=n;i++)
        a[i].v=a[i].l=a[i].r=read(),a[i].id=i,a[i].f=1;
    for (int i=1;i<=m;i++)
    {
        int x=read(),y=read();;
        a[x].l=min(a[x].l,y);
        a[x].r=max(a[x].r,y);
    }
    cdq(n,1,100000);
    int ans=0;
    for (int i=1;i<=n;i++) ans=max(a[i].f,ans);
    cout<<ans;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值