LG6168 [NOI Online #1 提高组] 冒泡排序(线段树/树状数组)

LG6168 [NOI Online #1 提高组] 冒泡排序

这个日好像不难,首先我们可以手算几组冒泡,我们可以发现一个特别的性质。

我们定义 \(c_i\),满足:

\[c_i=\sum\limits_{j=1}^{i-1} [a_j>a_i] \]

我们会发现,每进行一次冒泡,每个 \(c_i\) 都会减一,除非 \(c_i\) 已经等于 \(0\) 了。为什么呢?我们从冒泡排序的本质出发,每一轮对于 \([1,r]\) 这一个区间,是把这个区间内最大的数移到了最后一个位置。假设这个最大的数位置为 \(x\)。那么 \([x,r]\) 区间内每个 \(c_i\) 减小 \(1\) 很好理解。那么对于 \([1,x]\) 呢?那不是和 \([1,r]\) 一样的吗?所以递归证明即可。

有了这个性质,我们有:

\[ans=\sum\limits_{i=1}^n \max(0,c_i-k) \]

我们用权值线段树可以求出 \(c_i\),清空后,还可以再次也可以再次用于快速求出 \(ans\)就不想用树状数组哼!

时间复杂度 \(O(n\log n+m\log n)\)

//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
//#pragma GCC optimize("Ofast","-funroll-loops","-fdelete-null-pointer-checks")
//#pragma GCC target("ssse3","sse3","sse2","sse","avx2","avx")
#include<bits/stdc++.h>
#define int long long
using namespace std;

int read() {
	char ch=getchar();
	int f=1,x=0;
	while(ch<'0'||ch>'9') {
		if(ch=='-')
			f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') {
		x=x*10+ch-'0';
		ch=getchar();
	}
	return f*x;
}

const int MAXN=2e5+10; 

int n,m;
int a[MAXN],c[MAXN];
struct seg_tree {
	int sum,num;
}s[MAXN<<2];

void modify(int l,int r,int p,int x,int val) {
	if(r<x||x<l) {
		return ;
	}
	if(l==r) {
		s[p].num+=val;
		s[p].sum+=val*l;
		return ;
	}
	int mid=(l+r)>>1;
	modify(l,mid,p<<1,x,val);
	modify(mid+1,r,p<<1|1,x,val);
	s[p].sum=s[p<<1].sum+s[p<<1|1].sum;
	s[p].num=s[p<<1].num+s[p<<1|1].num;
}
int query_num(int l,int r,int p,int x,int y) {
	if(r<x||y<l) {
		return 0;
	}
	if(x<=l&&r<=y) {
		return s[p].num;
	}
	int mid=(l+r)>>1;
	return query_num(l,mid,p<<1,x,y)+query_num(mid+1,r,p<<1|1,x,y);
}
int query_sum(int l,int r,int p,int x,int y) {
	if(r<x||y<l) {
		return 0;
	}
	if(x<=l&&r<=y) {
		return s[p].sum;
	}
	int mid=(l+r)>>1;
	return query_sum(l,mid,p<<1,x,y)+query_sum(mid+1,r,p<<1|1,x,y);
}

signed main() {
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		cin>>a[i];
		c[i]=query_num(1,n,1,a[i]+1,n);
		modify(1,n,1,a[i],1);
	}
	memset(s,0,sizeof s);
	
	for(int i=1;i<=n;i++) {
		modify(1,n,1,c[i],1);
	}
	
	while(m--) {
		int opt,x;
		opt=read(),x=read();
		if(opt==1) {
			modify(1,n,1,c[x],-1);
			modify(1,n,1,c[x+1],-1);
			if(a[x]>a[x+1]) {
				swap(c[x],c[x+1]);
				swap(a[x],a[x+1]);
				c[x]--;
			}
			else {
				swap(c[x],c[x+1]);
				swap(a[x],a[x+1]);
				c[x+1]++;
			}
			modify(1,n,1,c[x],1);
			modify(1,n,1,c[x+1],1);
		}
		else {
			printf("%lld\n",query_sum(1,n,1,x+1,n)-x*query_num(1,n,1,x+1,n));
		}
	}
	return 0;
}

posted @ 2021-02-21 15:16  huayucaiji  阅读(73)  评论(0编辑  收藏  举报