1. 程式人生 > >洛谷P4331 [BOI2004]Sequence 數字序列(左偏樹)

洛谷P4331 [BOI2004]Sequence 數字序列(左偏樹)

傳送門

 

感覺……不是很看得懂題解在說什麼?

我們先把原數列$a_i-=i$,那麼本來要求遞增序列,現在只需要求一個非嚴格遞增的就行了(可以看做最後每個$b_i+=i$,那麼非嚴格遞增會變為遞增)

如果一個數列是遞增的,一個一個相等的取,如果是遞減的,取他們的中位數

前面的好理解,後面的想一下倉庫運輸那道題就明白了

然後我們現在把原數列分成了若干段答案相同的區間,考慮如何合併答案

如果$i$的答案小於等於$i+1$的答案,我們可以不做任何操作

那麼考慮$i$的答案大於$i+1$的答案,就合併它們的元素,取新的中位數即可,這個過程可以用可並堆來優化

然後大概就這樣了

 1 //minamoto
 2 #include<bits/stdc++.h>
 3 #define ll long long
 4 using namespace std;
 5 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
 6 char buf[1<<21],*p1=buf,*p2=buf;
 7 template<class T>inline bool cmax(T&a,const T&b){return
a<b?a=b,1:0;} 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return
res; 17 } 18 char sr[1<<21],z[20];int K=-1,Z; 19 inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;} 20 inline void print(int x){ 21 if(K>1<<20)Ot();if(x<0)sr[++K]=45,x=-x; 22 while(z[++Z]=x%10+48,x/=10); 23 while(sr[++K]=z[Z],--Z);sr[++K]=' '; 24 } 25 const int N=1e6+5; 26 int n,top;ll ans=0; 27 struct node{ 28 int l,r,sz,rt,val; 29 node(){} 30 node(int l,int r,int sz,int rt,int val):l(l),r(r),sz(sz),rt(rt),val(val){} 31 }st[N]; 32 int d[N],L[N],R[N],v[N]; 33 int merge(int x,int y){ 34 if(!x||!y) return x+y; 35 if(v[x]<v[y]) swap(x,y); 36 R[x]=merge(R[x],y); 37 if(d[L[x]]<d[R[x]]) swap(L[x],R[x]); 38 d[x]=d[R[x]]+1;return x; 39 } 40 int erase(int x){return merge(L[x],R[x]);} 41 int main(){ 42 // freopen("testdata.in","r",stdin); 43 n=read(); 44 for(int i=1;i<=n;++i) v[i]=read()-i; 45 st[top=1]=node(1,1,1,1,v[1]); 46 for(int i=2;i<=n;++i){ 47 st[++top]=node(i,i,1,i,v[i]); 48 while(top!=1&&st[top-1].val>st[top].val){ 49 --top; 50 st[top].rt=merge(st[top].rt,st[top+1].rt); 51 st[top].sz+=st[top+1].sz,st[top].r=st[top+1].r; 52 while(st[top].sz>(st[top].r-st[top].l+2)/2){ 53 --st[top].sz,st[top].rt=erase(st[top].rt); 54 } 55 st[top].val=v[st[top].rt]; 56 } 57 } 58 for(int i=1,p=1;i<=n;++i){ 59 if(st[p].r<i) ++p; 60 ans+=abs(st[p].val-v[i]); 61 } 62 printf("%lld\n",ans); 63 for(int i=1,p=1;i<=n;++i){ 64 if(st[p].r<i) ++p; 65 print(st[p].val+i); 66 } 67 Ot(); 68 return 0; 69 }