QOJ #2643. Bubble Sort 2
你要这样是吧。
首先这个题目有一个经典转化:冒泡排序次数相当于所有\(p_i\)的最大值,其中\(p_i=\sum\limits_{j=1}^{i-1}{[a_j>a_i]}\)。然后你就可以写出一个\(O(nq)\)的做法。
我们考虑将每个点\((i,a_i)\)放到平面上,那么这个值相当于每个点左上角的点数。因此如果对于\(i<j,a_i\geq a_j\),则\(i\)点是没用的。因此真正有用的是左下的凸壳上的点。
因为这个凸壳上的点一定是后缀最小值,因此答案可以表示为\(p_i=\sum\limits_{j=1}^{n}{[a_j>a_i]}-(n-i+1)\)。
然后你会发现,这个式子的优势是两维独立计算,因此考虑推广。如果直接将不在凸壳上的点强行套上这个式子,那么前一部分没有问题,后一部分会大于真实值,因为后面可能会有不在\([a_j+1,\infty]\)范围内的。因此总答案会变小。所以对原来的答案没有影响。因此写个线段树算对于每个点这个的最值就好了。
时间复杂度\(O(n\log n)\)。
感觉其实非常吃惊,因为就算单点修改,给单点求逆序对个数都是\(O(n\log^2n)\)的但是这个却能做到\(O(n\log n)\)。
实际实现的时候因为从\(0\)开始因此可能会有所区别。
code:
#include "bubblesort2.h"
#include<bits/stdc++.h>
#define Gc() getchar()
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) ((m)*(x-1)+(y))
#define R(n) (rnd()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using ll=long long;using db=double;using lb=long db;using ui=unsigned;using ull=unsigned ll;
using namespace std;const int N=5e5+5,M=N*8+5,K=2e3+5,mod=1e9+7,Mod=mod-1;const db eps=1e-5;const int INF=1e9+7;mt19937 rnd(time(0));
int n,m,A[N],Ts,x,Ns[N*2],Nh;set<int> f[N*2];vector<int> Answer;
namespace Tree{
#define ls v<<1
#define rs v<<1|1
int g[M],S[M];void Up(int v){S[v]=S[ls]+S[rs];g[v]=max(g[rs],g[ls]+S[rs]);}
void BD(int l=1,int r=Nh,int v=1){if(l==r){S[v]=f[l].size();g[v]=(f[l].empty()?-1e9:*f[l].rbegin());return;}int m=l+r>>1;BD(l,m,ls);BD(m+1,r,rs);Up(v);}
void Ins(int x,int l=1,int r=Nh,int v=1){if(l==r){S[v]=f[l].size();g[v]=(f[l].empty()?-1e9:*f[l].rbegin());return;}int m=l+r>>1;x<=m?Ins(x,l,m,ls):Ins(x,m+1,r,rs);Up(v);}
#undef ls
#undef rs
}
vector<int> countScans(vector<int> A,vector<int> X,vector<int> V){
int i,j;n=A.size();m=X.size();for(int i:A) Ns[++Nh]=i;for(int i:V) Ns[++Nh]=i;sort(Ns+1,Ns+Nh+1);Nh=unique(Ns+1,Ns+Nh+1)-Ns-1;
for(i=0;i<n;i++) A[i]=LB(Ns+1,Ns+Nh+1,A[i])-Ns;for(i=0;i<m;i++) V[i]=LB(Ns+1,Ns+Nh+1,V[i])-Ns;for(i=0;i<n;i++) f[A[i]].insert(i-n+1);Tree::BD();
for(i=0;i<m;i++)f[A[X[i]]].erase(X[i]-n+1),Tree::Ins(A[X[i]]),f[A[X[i]]=V[i]].insert(X[i]-n+1),Tree::Ins(A[X[i]]),Answer.PB(Tree::g[1]);return Answer;
}