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;
}