题解 小 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;
}
posted @ 2022-03-24 20:18  Administrator-09  阅读(5)  评论(0编辑  收藏  举报