題面
題意:
一個長度爲的排列,現在定義爲數組中下標小於等於並且小於的數字的和。現在給定,求。
思路:
首先可以肯定的是,中最後一個出現的位置在中一定是。我們可以反證:
假設不爲,假設在之前,那麼;假設在之後,那麼一定不是最後一個出現的位置,因爲當,那麼一定等於,因此最後一個出現的位置一定是,那麼我們把放到處。並且把之後的都減去.
其實對於從到的處理方法都一樣,對於第次操作,找到中最後一個爲的位置,令爲,然後對於所有的,讓。最終即可得到數組。對於上面的操作,可以用線段樹。
線段樹尋找最後一個的位置:從根節點出發,先看右子樹的最小值是否爲,如果是,去查右子樹,否則查左子樹。
最終複雜度
代碼:
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+100;
const int mod = 1e9+7;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const ll llINF = 0x3f3f3f3f3f3f3f3f;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fep(i,a,b) for(int i=(a);i>=(b);i--)
inline bool read(ll &num) {
char in;bool IsN=false;
in=getchar();
if(in==EOF) return false;
while(in!='-'&&(in<'0'||in>'9')) in=getchar();
if(in=='-'){ IsN=true;num=0;}
else num=in-'0';
while(in=getchar(),in>='0'&&in<='9'){
num*=10,num+=in-'0';
}
if(IsN) num=-num;
return true;
}
ll minn[N],sum[N],tag[N],p[N],a[N],n;
void pushup(ll rt){
minn[rt]=min(minn[rt<<1|1],minn[rt<<1]);
return ;
}
void pushdown(ll rt,ll l,ll r){
ll mid=(l+r)>>1;
tag[rt<<1]+=tag[rt];
tag[rt<<1|1]+=tag[rt];
minn[rt<<1]+=tag[rt];
minn[rt<<1|1]+=tag[rt];
tag[rt]=0;
}
void buildtree(ll rt,ll l,ll r){
tag[rt]=0;
if(l==r){
minn[rt]=p[l];
return ;
}
int mid=(l+r)>>1;
buildtree(rt<<1,l,mid);
buildtree(rt<<1|1,mid+1,r);
pushup(rt);
}
void modify(ll nl,ll nr,ll l,ll r,ll rt,ll k){//區間加減
if(nl<=l&&r<=nr){
tag[rt]+=k;
minn[rt]+=k;
return ;
}
ll mid=(l+r)>>1;
if(nl<=mid) modify(nl,nr,l,mid,rt<<1,k);
if(nr>mid) modify(nl,nr,mid+1,r,rt<<1|1,k);
pushup(rt);
}
ll ask(ll rt,ll l,ll r,ll nl,ll nr){//查詢區間最小值
if(nl<=l&&r<=nr){
return minn[rt];
}
pushdown(rt,l,r);
ll mid=(l+r)>>1;
ll ans=9999999999;
if(nl<=mid) ans=min(ans,ask(rt<<1,l,mid,nl,nr));
if(nr>mid) ans=min(ans,ask(rt<<1|1,mid+1,r,nl,nr));
return ans;
}
ll query(ll rt,ll l,ll r){//查找最後一個0的位置
if(l==r){
return l;
}
ll mid=(l+r)>>1;
if(ask(1,1,n,mid+1,r)==0) return query(rt<<1|1,mid+1,r);
else return query(rt<<1,l,mid);
pushup(rt);
}
int main(){
read(n);
rep(i,1,n) read(p[i]);
buildtree(1,1,n);
rep(i,1,n){
int id=query(1,1,n);
a[id]=i;
modify(id+1,n,1,n,1,-i);
modify(id,id,1,n,1,100000000000+i);//找到位置後把這個變成大數
}
rep(i,1,n) cout<<a[i]<<' ';
cout<<endl;
return 0;
}