http://www.elijahqi.win/archives/2949
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分治
首先得会这道题n^2的dp 这怎么写 设dp[i]表示以i结尾的符合要求的最长连续子序列 那么可以知道我需要满足一个偏序关系才可以设定fr表示这个数在变化中最小是fr to表示这个数在变化中最大是to a表示这个数初始是多少
考虑如果dp[j]可以更新dp[i]那么一定满足toj<=ai aj<=fri j< i那么可以看出实际上我需要找一个前面这样的最大的dp值来更新i的答案 那么就可以cdq来做了 把i,j看作是时间的一维度 每次分治的时候对to&a进行排序 然后做的时候用树状数组位数a,fr这一维 然后正常cdq分治即可
#include<cstdio>
#include<cctype>
#include<cstring>
#define N 100010
#include<algorithm>
using namespace std;
inline char gc(){
static char now[1<<16],*S,*T;
if(T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
return *S++;
}
inline int read(){
int x=0,f=1;char ch=gc();
while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
return x*f;
}
struct node{
int fr,a,to,id;
}data[N],tmp[N];
int mx,s[N],n,m,dp[N];
inline void add(int x,int v){while(x<=mx) s[x]=max(s[x],v),x+=x&-x;}
inline int query(int x){int tmp=0;while(x) tmp=max(tmp,s[x]),x-=x&-x;return tmp;}
inline void clear(int x){for (int i=x;i<=mx;i+=i&-i) if (!s[i]) return;else s[i]=0;}
inline bool cmpt(const node &a,const node &b){return a.to<b.to;}
inline bool cmpa(const node &a,const node &b){return a.a<b.a;}
inline bool cmpid(const node &a,const node &b){return a.id<b.id;}
inline void cdq(int l,int r){
if (l==r) return;int mid=l+r>>1;int now1=l,now2=mid+1;
for (int i=l;i<=r;++i)
if (data[i].id<=mid) tmp[now1]=data[i],++now1;else tmp[now2]=data[i],++now2;
memcpy(data+l,tmp+l,sizeof(node)*(r-l+1));cdq(l,mid);now1=l,now2=mid+1;
sort(data+l,data+mid+1,cmpt);sort(data+mid+1,data+r+1,cmpa);
while(now1<=mid&&now2<=r){
int id1=data[now1].id,id2=data[now2].id;
if (data[now1].to<=data[now2].a) add(data[now1].a,dp[id1]),++now1;else
dp[id2]=max(dp[id2],query(data[now2].fr)+1),++now2;
}int id2=0;
while(now2<=r) id2=data[now2].id,dp[id2]=max(dp[id2],query(data[now2].fr)+1),++now2;
for (int i=l;i<=r;++i) if (data[i].id<=mid) clear(data[i].a);
cdq(mid+1,r);
}
int main(){
// freopen("bzoj4553.in","r",stdin);
n=read();m=read();
for (int i=1;i<=n;++i) data[i].a=data[i].to=data[i].fr=read(),data[i].id=i,dp[i]=1,mx=max(mx,data[i].a);
for (int i=1;i<=m;++i){static int x,y;
x=read();y=read();data[x].fr=min(data[x].fr,y);data[x].to=max(data[x].to,y);
}cdq(1,n);int ans=0;
for (int i=1;i<=n;++i) ans=max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}