洛谷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 }
深深地明白自己的弱小