返回顶部

洛谷 P6186 [NOI Online #1 提高组] 冒泡排序 (权值树状数组)

  • 题意:RT

  • 题解:可以自己在纸上画画看,对于位置\(i\)的数\(a[i]\),假如它目前的逆序对数为\(c[i]\),进行一次冒泡排序后,它前面最大的一个数必然会移动到它的后面去,所以可以推广到:冒泡排序\(k\)次后,逆序对个数变为\(c[i]-k\).那么对某一状态的排列冒泡\(k\)次后,逆序对个数\(\le k\)的个数就没了,所以我们只要找逆序对个数大于\(k\)\(c[i]\),求个\(sum\),然后答案就是\(sum-k\),具体实现可以用两个权值树状数组分别维护逆序对个数和出现次数.

  • 代码:

    #include <bits/stdc++.h>
    #define ll long long
    #define fi first
    #define se second
    #define pb push_back
    #define me memset
    #define rep(a,b,c) for(int a=b;a<=c;++a)
    #define per(a,b,c) for(int a=b;a>=c;--a)
    const int N = 1e6 + 10;
    const int mod = 1e9 + 7;
    const int INF = 0x3f3f3f3f;
    using namespace std;
    typedef pair<int,int> PII;
    typedef pair<ll,ll> PLL;
    ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
    
    #define int long long 
    
    int n,m;
    int a[N];
    int c[2][N];
    int val[N];
    
    int lowbit(int x){
    	return x&(-x);
    }
    
    void add(int id,int i,int x){
    	if(i==0) return;
    	while(i<=n){
    		c[id][i]+=x;
    		i+=lowbit(i);
    	}
    }
    
    int get_sum(int id,int i){
    	int res=0;
    	if(i==0) return 0;
    	while(i){
    		res+=c[id][i];
    		i-=lowbit(i);
    	}
    	return res;
    }
    
    signed main() {
        ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	cin>>n>>m;
    	rep(i,1,n){
    		cin>>a[i];
    		add(0,a[i],1);
    		val[i]=i-get_sum(0,a[i]);
    	}
    	me(c,0,sizeof(c));
    
    	//建权值树状数组
    	rep(i,1,n){
    		add(0,val[i],1); //权值的个数
    		add(1,val[i],val[i]); //权值
    	}
    
    	while(m--){
    		int op,x;
    		cin>>op>>x;
    		if(op==1){
    			add(0,val[x],-1);
    			add(1,val[x],-val[x]);
    			add(0,val[x+1],-1);
    			add(1,val[x+1],-val[x+1]);
    			if(a[x]>a[x+1]) val[x+1]--;
    			else val[x]++;
    			swap(val[x],val[x+1]);
    			swap(a[x],a[x+1]);
    			add(0,val[x],1);
    			add(1,val[x],val[x]);
    			add(0,val[x+1],1);
    			add(1,val[x+1],val[x+1]);
    		}
    		else{
    			if(x>=n) {cout<<0<<'\n';continue;}
    			cout<<get_sum(1,n)-get_sum(1,x)-x*(get_sum(0,n)-get_sum(0,x))<<'\n';
    		}
    	}
    
        return 0;
    }
    
    
posted @ 2021-05-07 11:35  _Kolibri  阅读(95)  评论(0)    收藏  举报