洛谷 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; }
𝓐𝓬𝓱𝓲𝓮𝓿𝓮𝓶𝓮𝓷𝓽 𝓹𝓻𝓸𝓿𝓲𝓭𝓮𝓼 𝓽𝓱𝓮 𝓸𝓷𝓵𝔂 𝓻𝓮𝓪𝓵
𝓹𝓵𝓮𝓪𝓼𝓾𝓻𝓮 𝓲𝓷 𝓵𝓲𝓯𝓮

浙公网安备 33010602011771号