1. 程式人生 > >[BZOJ4553][HEOI2016]序列 CDQ分治

[BZOJ4553][HEOI2016]序列 CDQ分治

長度 main 讓我 can div ont 簡單的 可能 分析

4553: [Tjoi2016&Heoi2016]序列

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

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

Sample Input

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

Sample Output

3 題解: 我們來分析一下這道題讓我們幹什麽: 我們知道了一個序列,其中每一個元素都可能變化, 我們設他的原始值為a[i],最大值為maxv[i],最小值為minv[i], 再設f[i]為以i為結尾的最長符合要求子序列,顯然這可以用一個dp來解決:對於f[i],有   f[i]=max{f[j]}+1 而對j的要求,由於同時只有一個元素發生變化,我們就要求滿足   j<i&&maxv[j]<=a[i]&&a[j]<=minv[i] 我們發現,這好像長得“很像”一個三維偏序問題。 如果我們用樹套樹來解決的話,也不是不可以(詳見勇士的戰鬥記錄:BZOJ4553: [Tjoi2016&Heoi2016]序列 樹套樹優化DP) 但是為什麽我們不用更簡單的做法來解決呢? 顯然,這個東西是可以用cdq分治來解決的 我們對於區間[l,r],如果這個元素i在mi前面,我們就用(maxv[i],a[i])作為他的權值;否則,就用(a[i],minv[i])來作為他的權值。 這樣,就可以實現上面的想法了:用前面來更新後面。這也是本題的關鍵。 想到了這一點,代碼實現就很簡單了。代碼見下:
 1
#include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int N=300000; 7 int n,m,bit[N+100],f[N+100]; 8 struct num{int val,maxv,minv;}x[N+100]; 9 struct cdq{int x,y,id;}a[N+100]; 10 inline int lowbit(int a){return a&(-a);}
11 inline bool mt(const cdq &a,const cdq &b) 12 {return (a.x==b.x)?a.id<b.id:a.x<b.x;} 13 inline void add(int i,int val) 14 { 15 while(i<=N) 16 { 17 bit[i]=(val==0)?0:max(bit[i],val); 18 i+=lowbit(i); 19 } 20 } 21 inline int sum(int i) 22 { 23 int ret=0; 24 while(i) 25 ret=max(ret,bit[i]),i-=lowbit(i); 26 return ret; 27 } 28 void cdq(int l,int r) 29 { 30 if(l==r){f[l]=max(f[l],1);return;} 31 int mi=(l+r)>>1; 32 cdq(l,mi); 33 for(int i=l;i<=r;i++) 34 { 35 if(i<=mi)a[i].x=x[i].val,a[i].y=x[i].maxv; 36 else a[i].x=x[i].minv,a[i].y=x[i].val; 37 a[i].id=i; 38 } 39 sort(a+l,a+r+1,mt); 40 for(int i=l;i<=r;i++) 41 { 42 if(a[i].id<=mi)add(a[i].y,f[a[i].id]); 43 else f[a[i].id]=max(sum(a[i].y)+1,f[a[i].id]); 44 } 45 for(int i=l;i<=r;i++)add(a[i].y,0); 46 cdq(mi+1,r); 47 } 48 int main() 49 { 50 scanf("%d%d",&n,&m);int u,v,ans=0; 51 for(int i=1;i<=n;i++) 52 scanf("%d",&x[i].val),x[i].minv=x[i].maxv=x[i].val; 53 while(m--) 54 { 55 scanf("%d%d",&u,&v); 56 x[u].maxv=max(x[u].maxv,v); 57 x[u].minv=min(x[u].minv,v); 58 } 59 cdq(1,n); 60 for(int i=1;i<=n;i++)ans=max(ans,f[i]); 61 printf("%d\n",ans); 62 }

[BZOJ4553][HEOI2016]序列 CDQ分治