[LOJ535]「LibreOJ Round #6」花火

lojnode

description

給你一個排列$h_i$,你須要交換任意兩個位置上的數使得交換後排列的逆序對數最少。 $n \le 3\times 10^5$spa

sol

首先能夠發現,若是交換兩個位置$i,j(h_i>h_j)$,那麼逆序對數的減少量就是知足$i<k<j$且$h_j<h_k<h_i$的$k$的數量乘$2$。這至關於一個二維數點的問題。 理性分析一下,枚舉出來的$i$必定是前綴最大值,$j$必定是後綴最小值,否則這個矩形內包含的點的數量必定不是最多的。 那麼咱們就構造出了一個知足前綴最大的集合$U$和一個知足後綴最小的集合$D$,如今要從兩個集合中各選出一個構成一個矩形,最大化其中的點數。注意這兩個集合中的$h_i$都是單調遞增的。 咱們考慮每個點$(x,h_x)$會出如今哪些矩形中。 在$U$中二分找到最小的$l$知足$h_l>h_x$,在$D$中二分找到最小的$r$知足$h_r<h_x$,那麼要使點$(x,h_x)$被包含在$(i,j)$構成的矩形內部的條件就是:$i\in[l,x-1],j\in[x+1,r]$。 把點轉化爲矩陣,問題變成求矩形覆蓋的最大值,線段樹維護掃描線便可。 複雜度$O(n\log n)$。code

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 3e5+5;
int n,h[N],s1[N],t1,s2[N],t2,ins[N],cnt,mx[N<<2],tag[N<<2],c[N],ans;
long long sum;
struct node{
	int y,x1,x2,op;
	bool operator < (const node &b) const{
		if (y==b.y) return op<b.op;
		return y<b.y;
	}
}p[N<<1];
int binary1(int x){
	int l=1,r=t1,res=0;
	while (l<=r){
		int mid=l+r>>1;
		if (h[s1[mid]]>h[x]) res=mid,r=mid-1;
		else l=mid+1;
	}
	return s1[res];
}
int binary2(int x){
	int l=1,r=t2,res=0;
	while (l<=r){
		int mid=l+r>>1;
		if (h[s2[mid]]<h[x]) res=mid,r=mid-1;
		else l=mid+1;
	}
	return s2[res];
}
void modify(int x,int l,int r,int ql,int qr,int v){
	if (l>=ql&&r<=qr) {mx[x]+=v;tag[x]+=v;return;}
	int mid=l+r>>1;
	if (ql<=mid) modify(x<<1,l,mid,ql,qr,v);
	if (qr>mid) modify(x<<1|1,mid+1,r,ql,qr,v);
	mx[x]=max(mx[x<<1],mx[x<<1|1])+tag[x];
}
void mdf(int k){while(k<=n)++c[k],k+=k&-k;}
int qry(int k){int s=0;while(k)s+=c[k],k-=k&-k;return s;}
int main(){
	n=gi();
	for (int i=1;i<=n;++i) h[i]=gi();
	for (int i=1;i<=n;++i) if (i==1||h[i]>h[s1[t1]]) s1[++t1]=i,ins[i]=1;
	for (int i=n;i>=1;--i) if (i==n||h[i]<h[s2[t2]]) s2[++t2]=i,ins[i]=1;
	for (int i=1;i<=n;++i){
		if (ins[i]) continue;
		int l=binary1(i),r=binary2(i);
		if (l<i&&i<r){
			p[++cnt]=(node){i+1,l,i-1,1};
			p[++cnt]=(node){r+1,l,i-1,-1};
		}
	}
	sort(p+1,p+cnt+1);
	for (int i=1;i<=cnt;++i){
		modify(1,1,n,p[i].x1,p[i].x2,p[i].op);
		if (p[i].y!=p[i+1].y) ans=max(ans,mx[1]);
	}
	for (int i=n;i;--i) sum+=qry(h[i]-1),mdf(h[i]);
	printf("%lld\n",sum-2*ans);
	return 0;
}
相關文章
相關標籤/搜索