题解 小 Z 与函数
发现这是个选择排序
发现不算 vis 的话操作数是顺序对数
考虑这个 vis:
发现就是进行了交换的轮数
考虑对一个长度为 \(n\) 的排列做选择排序
那么发现做到位置 \(i\) 时 \(a_i=minn_i\),后面那个东西是前缀最小值
证明考虑只会将大数换进来
那么考虑每个位置 \(i\) 产生贡献的区间 \([pos_i, n]\)
当 \(minn_{i-1}=minn_i\) 时,\(pos_i\) 为 \([pos_{i-1}+1, n]\) 中第一个大于 \(minn_i\) 的数
否则 \(pos_i\) 为 \([i+1, n]\) 中第一个大于 \(minn_i\) 的数
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 200010
#define ll long long
//#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int n;
int a[N], b[N];
namespace force{
ll get(int n) {
ll res=0;
for(int i=1; i<=n; ++i) {
int vs=0;
for(int j=i; j<=n; ++j)
if (a[i]<a[j])
swap(a[i], a[j]), ++res, vs=1;
res+=vs;
// for (int j=1; j<=n; ++j) cout<<a[j]<<' '; cout<<endl;
}
return res;
}
void solve() {
for (int i=1; i<=n; ++i) {
for (int j=1; j<=i; ++j) a[j]=b[j];
printf("%lld ", get(i));
}
printf("\n");
}
}
namespace task{
bool vis[N];
int bit[N], minn[N], pos[N], tag[N];
inline void upd(int i) {for (; i<=n; i+=i&-i) ++bit[i];}
inline int query(int i) {int ans=0; for (; i; i-=i&-i) ans+=bit[i]; return ans;}
int tl[N<<2], tr[N<<2], mx[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define mx(p) mx[p]
#define pushup(p) mx(p)=max(mx(p<<1), mx(p<<1|1))
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r;
if (l==r) {mx(p)=b[l]; return ;}
int mid=(l+r)>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
}
int findmx(int p, int l, int r, int k) {
if (tl(p)==tr(p)) return mx(p)>k?tl(p):-1;
int mid=(tl(p)+tr(p))>>1;
if (l<=mid&&r>mid) {
int ans=findmx(p<<1, l, r, k);
if (~ans) return ans;
else return findmx(p<<1|1, l, r, k);
}
else if (l<=mid) return findmx(p<<1, l, r, k);
else return findmx(p<<1|1, l, r, k);
}
void solve() {
ll ans1=0, ans2=0;
memset(vis, 0, sizeof(vis));
memset(bit, 0, sizeof(bit));
memset(tag, 0, sizeof(tag));
memset(pos, 0, sizeof(pos));
minn[0]=INF; b[n+1]=INF;
for (int i=1; i<=n; ++i) minn[i]=min(minn[i-1], b[i]);
build(1, 1, n+1);
for (int i=1; i<=n; ++i) {
if (minn[i-1]==minn[i]) {
if (pos[i-1]!=n+1) ++tag[pos[i]=findmx(1, pos[i-1]+1, n+1, minn[i])];
else pos[i]=n+1;
}
else ++tag[pos[i]=findmx(1, i+1, n+1, minn[i])];
}
// cout<<"minn: "; for (int i=1; i<=n; ++i) cout<<minn[i]<<' '; cout<<endl;
// cout<<"pos: "; for (int i=1; i<=n; ++i) cout<<pos[i]<<' '; cout<<endl;
// cout<<"tag: "; for (int i=1; i<=n; ++i) cout<<tag[i]<<' '; cout<<endl;
for (int i=1; i<=n; ++i) {
ans1+=query(b[i]-1);
if (!vis[b[i]]) upd(b[i]), vis[b[i]]=1;
ans2+=tag[i];
printf("%lld ", ans1+ans2);
}
printf("\n");
}
}
signed main()
{
freopen("function.in", "r", stdin);
freopen("function.out", "w", stdout);
int T=read();
while (T--) {
n=read();
for (int i=1; i<=n; ++i) b[i]=read();
// force::solve();
task::solve();
}
return 0;
}