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