雅礼集训2019 Day1T2—Permutation(主席树)

给出 nn 个数AiA_i,

定义排列一个 11~nn 的排列 PP 的价值为:

inAiPi\sum_{i\le n}A_i*P_i

请你给出排列价值前 kk 小的 kk 个排列的价值。

n,k1e5n,k\le1e5

考虑k=1k=1
我们就是求一个排列得到i=1nApi(ni+1)\sum_{i=1}^{n}A_{p_i}*(n-i+1)最小
显然AA升序最小

现在考虑pp不动,每次改变AA

现在考虑我们如何从前kk小解拓展到k+1k+1
考虑每次选择一段区间[v,u][v,u],将Av=Av,AvA_v=A_v,A_{v} ~Au+1A_{u+1}依次像右移一位
显然一次的增量是l=1uvAuAul\sum_{l=1}^{u-v}A_{_u}-A_{_{u-l}}

显然所有解一定是这样拓展得到的
考虑对于一个pospos维护一个ll使得pospos向左拓展ll位增量最小
g(pos,l)g(pos,l)表示pospos往左拓展ll位的增量
那么有g(pos,l)g(pos,l+1)g(pos,l)\le g(pos,l+1)

那么每次我们就对于i=1n\sum_{i=1}^{n}维护一个Max(g(pos,lpos))Max(g(pos,l_{pos}))
考虑用一个主席树维护一下没有用过的AA
每一次拓展,也就是把AA循环位移一段[l,r][l,r]
就相当于删去[1,l1][1,l-1],并把这段加到rr后面

我们发现这样操作每次的ggll都可以直接维护(雾)
用个堆维护一下最小值就完了

#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);
	}
}
posted @ 2019-07-22 17:10  Stargazer_cykoi  阅读(191)  评论(0编辑  收藏  举报