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
1 2 3
1 2
2 3
2 1
3 4
Sample Output
3
HINT
注意题目里要求是所有情况下都满足,
用MAX(i)表示i位置能取的最大值,MIN(i)表示i位置能取的最小值,
那么对于一个i,假设有一个j,i和j能在序列里的条件是什么呢?
为了方便假设j<i,
那么MAX(j)<=a[i]并且a[j]<=MIN(i),注意只会改动一个数,讨论谁会改动即可。
由此我们就可以得到一个O(N^2)的dp了。。
然后考虑去优化它。
由于同时要满足两个条件
(事实上还有个j<i,所以实际上是三维偏序,
而j,i的顺序只要1~n枚举就直接确定了所以剩余一个二维偏序)
那么有两种方法,一种是cdq,考虑左区间对有区间的影响,树状数组搞搞即可
(我会说我不会吗= =);
还有就是暴力点的树套树了。。
由于求的是1~x中的最值,所以外层树状数组完全就可以搞了= =
内层则必须线段树或者平衡树了。。
而我一开始写了外层线段树,后面又懒得改了= =于是自信常数提交了一发。。
。。
17s,目前排名倒数第4……
幸好了写个splay都AC不了了。。。。
orz各位神犇都是1A的……我up写错结果WA了几次。。QAQ
#include<bits/stdc++.h>
using namespace std;
const int
N=100005,
Nlog=1800005;
int n,m,maxnum,ans,tot;
int a[N],MAX[N],MIN[N],root[N<<2];
struct Treap{
int l[Nlog],r[Nlog];
int NUM[Nlog],MAX[Nlog],rnd[Nlog],val[Nlog];
void up(int u){
MAX[u]=max(NUM[u],max(MAX[l[u]],MAX[r[u]]));
}
void lturn(int &u){
int t=r[u];r[u]=l[t],l[t]=u;
up(u),u=t,up(u);
}
void rturn(int &u){
int t=l[u];l[u]=r[t],r[t]=u;
up(u),u=t,up(u);
}
void insert(int &u,int x,int &tot,int y){
if (!u){
u=++tot;
NUM[u]=MAX[u]=y;
l[u]=r[u]=0,val[u]=x,rnd[u]=rand();
return;
}
MAX[u]=max(MAX[u],y);
if (x==val[u]){NUM[u]=max(NUM[u],y);return;}
if (x<val[u]){
insert(l[u],x,tot,y);
if (rnd[l[u]]<rnd[u]) rturn(u);
} else{
insert(r[u],x,tot,y);
if (rnd[r[u]]<rnd[u]) lturn(u);
}
}
void get_MAX(int u,int x){
if (!u) return;
if (val[u]<=x){
ans=max(ans,max(MAX[l[u]],NUM[u]));
get_MAX(r[u],x);
} else get_MAX(l[u],x);
}
}tr;
void update(int id,int l,int r,int g,int g1,int num){
tr.insert(root[id],g1,tot,num);
if (l==r) return;
int mid=(l+r)>>1;
if (g<=mid) update(id<<1,l,mid,g,g1,num);
else update(id<<1|1,mid+1,r,g,g1,num);
}
int query(int id,int l,int r,int gl,int gr,int num){
if (l>=gl && r<=gr){
ans=0,tr.get_MAX(root[id],num);
return ans;
}
int mid=(l+r)>>1,t=0;
if (gl<=mid) t=max(t,query(id<<1,l,mid,gl,gr,num));
if (gr>mid) t=max(t,query(id<<1|1,mid+1,r,gl,gr,num));
return t;
}
int main(){
srand(123215);
scanf("%d%d",&n,&m),maxnum=0;
for (int i=1;i<=n;i++)
scanf("%d",&a[i]),MAX[i]=MIN[i]=a[i],
maxnum=max(maxnum,a[i]);
int x,y;
for (int i=1;i<=m;i++){
scanf("%d%d",&x,&y);
maxnum=max(maxnum,y);
MAX[x]=max(MAX[x],y),MIN[x]=min(MIN[x],y);
}
tot=0;int ANS=1;
update(1,1,maxnum,a[1],MAX[1],1);
for (int i=2;i<=n;i++){
int t=query(1,1,maxnum,1,MIN[i],a[i])+1;
update(1,1,maxnum,a[i],MAX[i],t);
ANS=max(ANS,t);
}
printf("%d\n",ANS);
return 0;
}