BZOJ4553: [Tjoi2016&Heoi2016]序列
BZOJ4553: [Tjoi2016&Heoi2016]序列
Description
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。
玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。
现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?
请你告诉她这个子序列的最长长度即可。
注意:每种变化最多只有一个值发生变化。
在样例输入中,所有的变化是:
1 2 3
2 2 3
1 3 3
1 1 3
1 2 4
选择子序列为原序列,即在任意一种变化中均为不降子序列。
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
题解Here!
很烦人的一题。。。
蒟蒻表示并不会整体二分/cdq分治,只能弱弱地打出树状数组套平衡树。。。
关键是我的 Splay 还写挂了,药丸。。。
我们设:
maxvi 为第 i 个数变化的最大值;
minvi 为第 i 个数变化的最小值;
ai 为原来的数值。
则题目要求转化为:
求一个最长的序列,使一下条件满足 j < i,max( aj , maxvj ) ≤ ai .
那这种不等式问题就能转化为二维数点问题。
对于每一个 j ,我们每一次就可以在平面内加一个坐标为 ( maxvj , aj ) 的权值为 dp[ j ] 的点;
对于每一次转移,可以从 (0,0) 到 ( ai , minvi ) 中找到一个点权最大的点,当前点答案就是找到点的权值+1。
附代码:
#include<iostream> #include<algorithm> #include<cstdio> #define MAXN 200010 using namespace std; int n,m,maxn=0; int num[MAXN],b[MAXN],c[MAXN],dp[MAXN]; int size=1; struct node{ node* son[2]; int w,v,x,maxn; node(){ son[0]=son[1]=NULL; w=rand(); } }; node* root[MAXN]; inline int read(){ int date=0,w=1;char c=0; while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();} while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();} return date*w; } inline int max(const int x,const int y){return x>y?x:y;} inline void maintain(node* &u){ if(u==NULL)return; u->maxn=u->v; if(u->son[0]!=NULL)u->maxn=max(u->maxn,u->son[0]->maxn); if(u->son[1]!=NULL)u->maxn=max(u->maxn,u->son[1]->maxn); } inline void turn(node* &u,int f){ node* t=u->son[f^1]; u->son[f^1]=t->son[f]; t->son[f]=u; maintain(u); maintain(t); u=t; } void insert(node* &u,int x,int v){ if(u==NULL){ u=new node; u->x=x;u->v=u->maxn=v; maintain(u); return; } else if(u->x==x){ u->v=max(u->v,v); maintain(u); return; } int y=u->x<x?1:0; insert(u->son[y],x,v); if(u->son[y]->w>u->w)turn(u,y^1); maintain(u); } int query(node* u,int x){ int s=0; while(u!=NULL){ if(u->x>x)u=u->son[0]; else{ if(u->son[0]!=NULL)s=max(s,max(u->son[0]->maxn,u->v)); else s=max(s,u->v); u=u->son[1]; } } return s; } inline int lowbit(int x){return x&(-x);} void update(int x,int y,int v){ for(int i=x;i<=maxn;i+=lowbit(i))insert(root[i],y,v); } int get_max(int x,int y){ int s=0; for(int i=x;i;i-=lowbit(i))s=max(s,query(root[i],y)); return s; } void work(){ int ans=0; for(int i=1;i<=n;i++){ dp[i]=get_max(b[i],num[i])+1; ans=max(ans,dp[i]); update(num[i],c[i],dp[i]); } printf("%d\n",ans); } void init(){ int x,y; n=read();m=read(); for(int i=1;i<=n;i++)b[i]=c[i]=num[i]=read(); for(int i=1;i<=m;i++){ x=read();y=read(); b[x]=min(b[x],y); c[x]=max(c[x],y); } for(int i=1;i<=n;i++)maxn=max(maxn,c[i]); } int main(){ srand(798); init(); work(); return 0; }