BZOJ4553: [Tjoi2016&Heoi2016]序列
Description
佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他。
玩具上有一个数列,数列中某些项的值可能会变化,但同一个时刻最多只有一个值发生变化。
现在佳媛姐姐已经研究出了所有变化的可能性,她想请教你,能否选出一个子序列,使得在任意一种变化中,这个子序列都是不降的?
请你告诉她这个子序列的最长长度即可。
注意:每种变化最多只有一个值发生变化。
在样例输入中,所有的变化是:
Input
输入的第一行有两个正整数n, m,分别表示序列的长度和变化的个数。
接下来一行有n个数,表示这个数列原始的状态。
接下来m行,每行有2个数x, y,表示数列的第x项可以变化成y这个值。
1 <= x <= n。所有数字均为正整数,且小于等于100,000
Output
输出一个整数,表示对应的答案
Sample Input
1 2 3
1 2
2 3
2 1
3 4
Sample Output
很烦人的一题。。。
蒟蒻表示并不会整体二分/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;
}