zoukankan      html  css  js  c++  java
  • 雅礼集训2019 Day1T2—Permutation(主席树)

    给出 nn 个数AiA_i,

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

    inAiPisum_{ile n}A_i*P_i

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

    n,k1e5n,kle1e5

    考虑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=1uvAuAulsum_{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=1nsum_{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<<'
    ';
    	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<<'
    ';
    		calc(now.se);
    	}
    }
    
  • 相关阅读:
    24、面向对象(内置方法)
    23、面向对象(包装)
    22、面向对象(反射)
    21、面向对象(封装)
    20、面向对象(多态)
    19、面向对象(继承)
    18、面向对象(静态属性、类方法、静态方法)
    LeetCode 3. Longest Substring Without Repeating Characters
    LeetCode 2.Add Two Numbers
    LeetCode 1. Two Sum
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328774.html
Copyright © 2011-2022 走看看