1. 程式人生 > >[bzoj 4553][Tjoi2016&Heoi2016]序列

[bzoj 4553][Tjoi2016&Heoi2016]序列

傳送門

Description

佳媛姐姐過生日的時候,她的小夥伴從某寶上買了一個有趣的玩具送給他。玩具上有一個數列,數列中某些項的值可能會變化,但同一個時刻最多隻有一個值發生變化。現在佳媛姐姐已經研究出了所有變化的可能性,她想請教你,能否選出一個子序列,使得在任意一種變化中,這個子序列都是不降的?請你告訴她這個子序列的最長長度即可。注意:每種變化最多隻有一個值發生變化。在樣例輸入1中,所有的變化是:

1 2 3
2 2 3
1 3 3
1 1 3
1 2 4

選擇子序列為原序列,即在任意一種變化中均為不降子序列在樣例輸入2中,所有的變化是:3 3 33 2 3選擇子序列為第一個元素和第三個元素,或者第二個元素和第三個元素,均可滿足要求

Solution

每個元素加下三個值:原值x,最大值ma,最小值mi

前後兩個元素(a,b)要滿足:

  • \(a.x \leq b.mi\)
  • \(a.ma \leq b.x\)

\(dp[i]=\max_{j} dp[j]+1\),其中j,i滿足上面兩個條件

cdq求三維偏序即可,但是條件的左右屬性是不一樣的,所以要對(l,mid)和(mid+1,r)分別按照x和mi來排序

複雜度是\(O(n \log^2 n)\)


Code 

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
#define MN 100005
struct Node{int x,ma,mi,id;}a[MN];
inline bool cmp1(const int&o,const int&oo){return a[o].x<a[oo].x;}
inline bool cmp2(const int&o,const int&oo){return a[o].mi<a[oo].mi;}
int n,m,t[MN],f[MN],id[MN];

#define lb(x) (x&(-x))
inline void C(int x,int v){for(;x<MN;x+=lb(x)) t[x]=max(t[x],v);}
inline int G(int x){int r=0;for(;x;x-=lb(x)) r=max(r,t[x]);return r;}
inline void C0(int x){for(;x<MN;x+=lb(x)) t[x]=0;}

void solve(int l=1,int r=n)
{
//  x.val<=y.min
//  x.max<=y.val    
    if(l==r) return;
    int mid=(l+r)>>1;
    solve(l,mid);
    
    register int i,j;
    for(i=l;i<=r;++i) id[i]=i;

    std::sort(id+l,id+mid+1,cmp1);
    std::sort(id+mid+1,id+r+1,cmp2);

    for(j=l,i=mid+1;i<=r;++i)
    {
        for(;j<=mid&&a[id[j]].x<=a[id[i]].mi;++j) C(a[id[j]].ma,f[a[id[j]].id]);
        f[a[id[i]].id]=max(f[a[id[i]].id],G(a[id[i]].x)+1);
    }
    for(i=l;i<=mid;++i) C0(a[id[i]].ma);
    solve(mid+1,r);
}
int main()
{
    n=read();m=read();
    register int i,v;
    for(i=1;i<=n;++i) a[i].id=i,a[i].x=a[i].mi=a[i].ma=read(),f[i]=1;
    while(m--)
    {
        i=read();v=read();
        a[i].ma=max(a[i].ma,v);
        a[i].mi=min(a[i].mi,v);
    }
    solve();
    register int ans=0;
    for(i=1;i<=n;++i) ans=max(ans,f[i]);
    printf("%d\n",ans);
    return 0;
}



Blog來自PaperCloud,未經允許,請勿轉載,TKS!