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

Sample Output

3
题解Here!

很烦人的一题。。。

蒟蒻表示并不会整体二分/cdq分治,只能弱弱地打出树状数组套平衡树。。。

关键是我的 Splay 还写挂了,药丸。。。

我们设:

maxvi 为第 i 个数变化的最大值;

minvi 为第 i 个数变化的最小值;

ai 为原来的数值。

则题目要求转化为:

求一个最长的序列,使一下条件满足 i,maxaj​ 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;
}

 

posted @ 2018-07-16 00:44  符拉迪沃斯托克  阅读(211)  评论(0编辑  收藏  举报
Live2D