BZOJ4553 || 洛谷P4093 [HEOI2016/TJOI2016]序列【DP+CDQ分治】

Time Limit: 20 Sec
Memory Limit: 128 MB

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

輸出一個整數,表示對應的答案


題目分析

大匹方程是是老套路了, dp[i]dp[i]表示以viv_i結尾的最長不下降子序列
dp[i]=max(dp[j])+1 (ji,maxjvi,vjmini)dp[i]=max(dp[j])+1\ (j\leq i,max_j\leq v_i,v_j\leq min_i)
觀察這裏的轉移限制條件,不就是三維偏序嘛
CDQ分治優化DP即可

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x)) 

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int inf=1e9;
const int maxn=100010;
int n,m;
struct node{int val,mi,mx,id,ans;}a[maxn],b[maxn];
int mx[maxn];

void update(int x,int v){ for(int i=x;i<=n;i+=lowbit(i))mx[i]=max(mx[i],v);}
int qmax(int x){ int res=0; for(int i=x;i>0;i-=lowbit(i))res=max(res,mx[i]); return res;}
void cls(int x){ for(int i=x;i<=n;i+=lowbit(i))mx[i]=0;}

bool cmp1(node x,node y){return x.mx<y.mx;} 
bool cmp2(node x,node y){return x.val<y.val;}
bool cmp3(node x,node y){return x.id<y.id;}

void CDQ(int ll,int rr)
{
    if(ll==rr) return;
    int mid=ll+rr>>1;
    CDQ(ll,mid);
    
    sort(a+ll,a+mid+1,cmp1); 
    sort(a+mid+1,a+rr+1,cmp2);
    
    int t1=ll,t2=mid+1;
    while(t2<=rr)
    {
        while(a[t1].mx<=a[t2].val&&t1<=mid)
        update(a[t1].val,a[t1].ans),t1++;
        a[t2].ans=max(a[t2].ans,qmax(a[t2].mi)+1); t2++;
    }
    
    for(int i=ll;i<t1;++i) 
    cls(a[i].val);
    
    sort(a+mid+1,a+rr+1,cmp3);
    CDQ(mid+1,rr);
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i) 
    {
        a[i].val=a[i].mi=a[i].mx=read();
        a[i].id=i; a[i].ans=1;
    }
    
    for(int i=1;i<=m;++i)
    {
        int x=read(),y=read();
        a[x].mi=min(a[x].mi,y); 
        a[x].mx=max(a[x].mx,y);
    }
    
    CDQ(1,n); int ans=0;
    for(int i=1;i<=n;++i) 
    ans=max(ans,a[i].ans);
    
    printf("%d",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章