https://ac.nowcoder.com/acm/contest/62977/H
链接:https://ac.nowcoder.com/acm/contest/62977/H
来源:牛客网
给定一个由 n n n 个正整数组成的序列 a a a ,你可以通过 j − i j−i j−i 个花费交换 a i , a j ( j > i ) a_i,a_j(j>i) ai,aj(j>i) 两个元素。
我们定义一个位置 i i i 是好的,当且仅当 a i a_i ai 不与其他元素发生交换的前提下,使得 a 1 , . . . , a i − 1 ≤ a i a_1,...,a_{i-1}\le a_i a1,...,ai−1≤ai ,即位置 1 ∼ i − 1 1\sim i-1 1∼i−1 上的元素均小于等于 a i a_i ai 。请注意,满足上述要求并不需要 1 ∼ i − 1 1\sim i-1 1∼i−1 中元素有序,只需要满足与 a i a_i ai 的相对大小关系即可。
对于所有的 i ∈ { 1 , 2 , . . . , n } i\in \{1,2,...,n\} i∈{1,2,...,n} 分别求出使位置 i i i 是好的所需要的最小花费是多少。如果怎么操作都无法使 i i i 位置是好的,则输出 − 1 -1 −1 。
对于每个 i i i ,进行的操作是相互独立的,并没有真正修改原数组的位置。
对于 ∑ j − i \sum j-i ∑j−i,可以拆分成 ∑ j − ∑ i \sum j-\sum i ∑j−∑i,对于每个确定的 k k k,在 a 1 , . . . , a k − 1 a_1,...,a_{k-1} a1,...,ak−1中小于等于 a k a_k ak的我们显然不需要去管它,只需挑出大于 a k a_k ak的 m m m个交换,所以 ∑ i \sum i ∑i是确定的,只要在 a l + 1 , . . . , a n a_{l+1},...,a_n al+1,...,an中挑出 m m m个下标最小的小于等于 a k a_k ak的即可。
求取 a 1 , . . . , a k − 1 a_1,...,a_{k-1} a1,...,ak−1中大于 a k a_k ak的数的个数和下标和,可以用线段树。将 a a a从大到小排序,按序计算,对于已经处理过的打上标记,表明其大于之后的数,对于每一个 i i i求取 1 ∼ i − 1 1\sim i-1 1∼i−1中大于其的数的个数与下标和,记为 m , s u m 1 m,sum1 m,sum1,再在 i + 1 ∼ n i+1\sim n i+1∼n中求取 m m m个下表最小的小于等于 a i a_i ai的数,可以在线段树上二分查找,记下下标和 s u m 2 sum2 sum2,答案为 s u m 2 − s u m 1 sum2-sum1 sum2−sum1
#include
#define ll long long
using namespace std;
const int N=1e5+5;
struct node{
int sum;ll x;
node operator +(const node a){
return node{sum+a.sum,x+a.x};
}
};
struct tree{
node tr[N<<3];
void pushup(int res){tr[res]=tr[res<<1]+tr[res<<1|1];}
void add(int res,int l,int r,int x,int op){
if(l==r){
tr[res].x=x*op,tr[res].sum=op;
return;
}
int mid=l+r>>1;
if(mid>=x)add(res<<1,l,mid,x,op);
else add(res<<1|1,mid+1,r,x,op);
pushup(res);
}
node query(int res,int l,int r,int x,int y){
if(y=r){
return tr[res];
}
int mid=l+r>>1;
if(mid>=y)return query(res<<1,l,mid,x,y);
if(mid>1;
if(y<=mid)
return q3(res<<1,l,mid,x,y,w);
else if(x>=mid+1)
return q3(res<<1|1,mid+1,r,x,y,w);
else
{
node lq=q3(res<<1,l,mid,x,mid,w);
if(lq.sum==w)
return lq;
node rq=q3(res<<1|1,mid+1,r,mid+1,y,w-lq.sum);
return lq+rq;
}
}
void build(int res,int l,int r){
if(l==r){
tr[res].sum=1,tr[res].x=l;
return;
}
int mid=l+r>>1;
build(res<<1,l,mid);
build(res<<1|1,mid+1,r);
pushup(res);
}
}a1,a2;
struct Node{
int x,id;
}b[N<<2];
bool cmp(Node a,Node b){
return a.x>b.x;
}
ll n,a[N<<2],c[N<<2];
ll work(int x){
// cout<>n;
for(int i=1;i<=n;i++)cin>>a[i],b[i].x=a[i],b[i].id=i;
a2.build(1,1,n);
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++){
if(b[i].x!=b[i-1].x){
int j=1;
while(i-j>0&&b[i-j].x==b[i-1].x)a1.add(1,1,n,b[i-j].id,1),a2.add(1,1,n,b[i-j].id,0),j++;
}
c[b[i].id]=work(b[i].id);
}
for(int i=1;i<=n;i++)cout<