雅礼集训2019 Day1T2—Permutation(主席树)
给出 个数,
定义排列一个 ~ 的排列 的价值为:
请你给出排列价值前 小的 个排列的价值。
考虑时
我们就是求一个排列得到最小
显然升序最小
现在考虑不动,每次改变
现在考虑我们如何从前小解拓展到小
考虑每次选择一段区间,将 ~依次像右移一位
显然一次的增量是
显然所有解一定是这样拓展得到的
考虑对于一个维护一个使得向左拓展位增量最小
记表示往左拓展位的增量
那么有
那么每次我们就对于维护一个
考虑用一个主席树维护一下没有用过的
每一次拓展,也就是把循环位移一段
就相当于删去,并把这段加到后面
我们发现这样操作每次的和都可以直接维护(雾)
用个堆维护一下最小值就完了
#include<bits/stdc++.h>
using namespace std;
#define gc getchar
inline int read(){
char ch=gc();
int res=0,f=1;
while(!isdigit(ch))f^=ch=='-',ch=gc();
while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
return f?res:-res;
}
#define re register
#define pii pair<ll,int>
#define pb push_back
#define fi first
#define se second
#define cs const
#define ll long long
const int N=100005;
const ll inf=1e18;
int n,a[N];
namespace Seg{
#define M N*101
#define mid ((l+r)>>1)
int tt;
struct node{
int pos,len,siz,lc,rc;ll mx;
}tr[M];
#define lc tr[u].lc
#define rc tr[u].rc
inline void build(int &u,int l,int r){
u=++tt,tr[u].siz=r-l+1;
if(l==r)return;
build(lc,l,mid),build(rc,mid+1,r);
}
inline void pushup(int u){
if(tr[lc].mx<tr[rc].mx)tr[u].pos=tr[lc].pos,tr[u].len=tr[lc].len,tr[u].mx=tr[lc].mx;
else tr[u].pos=tr[lc].siz+tr[rc].pos,tr[u].len=tr[rc].len,tr[u].mx=tr[rc].mx;
tr[u].siz=tr[lc].siz+tr[rc].siz;
}
inline void insert(int l,int r,int &r1,int k,ll mx){
int u=++tt;tr[u]=tr[r1],r1=u;
if(!lc&&!rc){
tr[u].len++,tr[u].pos=tr[u].siz=1,tr[u].mx+=mx;
return;
}
if(tr[lc].siz>=k)insert(l,mid,lc,k,mx);
else insert(mid+1,r,rc,k-tr[lc].siz,mx);
pushup(u);
}
inline void update(int &r1,int k,ll mx,int siz){
int u=++tt;tr[u]=tr[r1],r1=u;
if(!lc&&!rc){
tr[u].pos=tr[u].siz=siz,tr[u].mx=mx;return;
}
if(tr[lc].siz>=k)update(lc,k,mx,siz);
else update(rc,k-tr[lc].siz,mx,siz);
pushup(u);
}
inline void delet(int &r1,int k){
if(!k)return;
int u=++tt;tr[u]=tr[r1],r1=u;
if(tr[lc].siz>k)delet(lc,k);
else k-=tr[lc].siz,lc=0,delet(rc,k);
pushup(u);
}
inline int query(int u,int l,int r,int k){
if(l==r)return a[l];
if(tr[lc].siz>=k)return query(lc,l,mid,k);
return query(rc,mid+1,r,k-tr[lc].siz);
}
}
using namespace Seg;
struct data{
int rt,nxt;ll mx;
}p[N];
int tot;
priority_queue<pii,vector<pii>,greater<pii> > q;
inline void calc(int pre){
int u=p[pre].rt;
p[++tot].mx=p[pre].mx+tr[u].mx;
p[tot].rt=p[pre].nxt;
int pos=tr[u].pos,len=tr[u].len,last=pos-len;
update(p[tot].rt,pos,inf,0);
if(last>1)delet(p[tot].rt,last-1);
if(len<tr[p[tot].rt].siz)update(p[tot].rt,len+1,query(p[tot].rt,1,n,len+1)-query(p[tot].rt,1,n,len),1);
update(p[tot].rt,1,inf,1);
p[tot].nxt=p[tot].rt;
q.push(pii(p[tot].mx+tr[p[tot].rt].mx,tot));
if(pos>len+1)insert(1,n,p[pre].rt,pos,query(p[pre].rt,1,n,pos)-query(p[pre].rt,1,n,pos-len-1));
else insert(1,n,p[pre].rt,pos,inf);
q.push(pii(p[pre].mx+tr[p[pre].rt].mx,pre));
}
signed main(){
#ifdef Stargazer
freopen("lx.cpp","r",stdin);
#endif
n=read();int k=read();
for(int i=1;i<=n;i++)a[i]=read();
sort(a+1,a+n+1);
tr[0].mx=inf,build(p[0].rt,1,n);
for(int i=1;i<=n;i++){
p[0].mx+=1ll*a[i]*(n-i+1);
if(i>1)insert(1,n,p[0].rt,i,a[i]-a[i-1]);
else insert(1,n,p[0].rt,i,inf);
}
p[0].nxt=p[0].rt;
cout<<p[0].mx<<'\n';
q.push(pii(p[0].mx+tr[p[0].rt].mx,0));
for(int i=1;i<k;i++){
pii now=q.top();q.pop();
cout<<now.fi<<'\n';
calc(now.se);
}
}