1. 程式人生 > >BZOJ4553:[HEOI2016/TJOI2016]序列——題解

BZOJ4553:[HEOI2016/TJOI2016]序列——題解

get 發生 給他 algo tps struct cstring code In

https://www.lydsy.com/JudgeOnline/problem.php?id=4553

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

1 2 3 2 2 3 1 3 3 1 1 3 1 2 4 選擇子序列為原序列,即在任意一種變化中均為不降子序列

一道比較難的題?可能是我CDQ很久沒寫的緣故了……

設l[i]~r[i]表示i數的變動範圍,考慮f[i]=max(f[j])+1,其中j要滿足:

j<i

a[j]<=l[i]

r[j]<=a[i]

很顯然是CDQ三維(?)偏序的模型,但是有四個變量,所以歸並排序貌似不可做……

改一下變量名變成:

tj<ti

xj<=yi

zj<=xi

我們一維排t,二維mid左右兩邊分別排x和y,然後按照順序類似歸並排序把兩邊的x和y合在一起,再用樹狀數組維護第三維就好啦!

當然註意每次我們處理完別忘了要回歸原位!

#include<map>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<vector>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long
long ll; const int N=1e5+5; const int MAX=1e5; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch==-;ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int x,y,z,t,ans; }a[N]; int n,m,tr[N]; inline int lowbit(int x){return x&(-x);} inline void add(int x,int y){ for(int i=x;i<=MAX;i+=lowbit(i))tr[i]=max(tr[i],y); } inline int query(int x){ int res=0; for(int i=x;i;i-=lowbit(i))res=max(res,tr[i]); return res; } inline void mdy(int x){ for(int i=x;i<=MAX;i+=lowbit(i))tr[i]=0; } inline bool cmpt(node a,node b){ return a.t<b.t; } inline bool cmpx(node a,node b){ return a.x==b.x?a.t<b.t:a.x<b.x; } inline bool cmpy(node a,node b){ return a.y==b.y?a.t<b.t:a.y<b.y; } void cdq(int l,int r){ if(l>=r)return; int mid=(l+r)>>1; cdq(l,mid); sort(a+l,a+mid+1,cmpx); sort(a+mid+1,a+r+1,cmpy); for(int i=l,j=l,k=mid+1;i<=r;i++){ if(j<=mid&&(k>r||a[j].x<=a[k].y))add(a[j].z,a[j].ans),j++; else a[k].ans=max(a[k].ans,query(a[k].x)+1),k++; } for(int i=l;i<=mid;i++)mdy(a[i].z); sort(a+mid+1,a+r+1,cmpt); cdq(mid+1,r); } int main(){ n=read(),m=read(); for(int i=1;i<=n;i++)a[i].x=a[i].y=a[i].z=read(),a[i].t=i; for(int i=1;i<=m;i++){ int x=read(),y=read(); a[x].y=min(a[x].y,y); a[x].z=max(a[x].z,y); } for(int i=1;i<=n;i++)a[i].ans=1; cdq(1,n); int ans=0; for(int i=1;i<=n;i++)ans=max(ans,a[i].ans); printf("%d\n",ans); return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4553:[HEOI2016/TJOI2016]序列——題解