P14030 【MX-X20-T4】「FAOI-R7」连接时光 I题解
sword7level · · 题解
题意:
题目说给定一个长度为
题目分析:
我们先考虑都是正数的情况肯定就是边越多越好,对于每个点
我们现在要使负数的点和正数的点联通且负数边权使用的尽量少,是负数边权尽量小,我们就先让正数点不贡献负数边权,即为将正数点从
为了不增加新的负贡献,我们只能连一条边,我们考虑每一个块的倒数第二个已经是最大的了再大一点也对当前块没有影响,下一个块的最后一个已经是下一个块最小的了再小一点对下一个块没有影响,它们交换后对两块之间也没有额外的贡献,我们就将下一个块的最后一个和这一个块的倒数第二个交换即可。若这个块长度为一,我们不难发现直接交换最后一个就可以了。
最后需要将负数块连向正数块,我们肯定还是选择负数块的最大权值,我们考虑不增加新的贡献就一定要交换前面最大的位置,这一定小于负数块最小的位置大于前面其他位置,前面若有负数就交换前面最后一个负数位置,否则就交换第一个正数位置,将它与第一个负数块的最后一个位置交换即可。
我们构造出来排列后就直接树状数组统计逆序对算答案即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
#define ll long long
inline ll read(){
ll w=0,f=1;
char ch=getchar();
while(ch<'0' || '9'<ch){
if(ch=='-') f=-1;
ch=getchar();
}
while('0'<=ch && ch<='9'){
w=(w<<3)+(w<<1)+(ch^48);
ch=getchar();
}
return w*f;
}
inline void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>=10) write(x/10);
putchar(x%10+'0');
}
int t,n,a[N],nxt[N];
ll c[N];
struct BIT{
int tree[N];
inline int lowbit(int x){
return x&(-x);
}
inline void add(int x,int k){
while(x<=n){
tree[x]+=k;
x+=lowbit(x);
}
}
inline int query(int x){
int res=0;
while(x){
res+=tree[x];
x-=lowbit(x);
}
return res;
}
inline void clear(){
for(int i=1;i<=n;i++) tree[i]=0;
return;
}
}tree;
signed main(){
cin.tie(0);cout.tie(0);
t=read();
while(t--){
n=read();
for(int i=1;i<=n;i++) c[i]=read(),a[i]=0,nxt[i]=0;
int pos=0;
for(int i=n;i>=1;i--){
if(c[i]>=0){
pos=i;
break;
}
}
vector<int> v;
nxt[n]=n;
v.push_back(n);
for(int i=n-1;i>pos;i--){
if(c[i]>=c[nxt[i+1]]){
nxt[i]=i;
v.push_back(i);
}else nxt[i]=nxt[i+1];
}
v.push_back(pos);
int cnt=n;
for(int i=0;i<v.size()-1;i++){
for(int j=v[i]-1;j>v[i+1];j--) a[j]=cnt--;
a[v[i]]=cnt--;
if(i>0){
if(v[i]-1-v[i+1]>0) swap(a[v[i]-1],a[v[i-1]]);
else swap(a[v[i]],a[v[i-1]]);
}
}
cnt=1;
for(int i=pos;i>=1;i--){
if(c[i]>=0) a[i]=cnt++;
}
int last=1;
for(int i=1;i<pos;i++) if(c[i]<0) a[i]=cnt++,last=i;
//cerr<<v.size()<<' '<<pos<<'\n';
if(pos && pos!=n) swap(a[last],a[v[v.size()-2]]);
ll ans=0;
tree.clear();
for(int i=1;i<=n;i++){
ans+=(tree.query(n)-tree.query(a[i]))*c[i];
tree.add(a[i],1);
}
write(ans);putchar('\n');
for(int i=1;i<=n;i++) write(a[i]),putchar(' ');
putchar('\n');
}
return 0;
}