ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【DS】loj#535. 「LibreOJ Round #6」花火

2022-02-08 18:04:32  阅读:196  来源: 互联网

标签:cur LibreOJ cl loj res mid int 最小值 Round


题传

真难写,,

考虑冒泡排序,每一次交换相邻的减少 1 对逆序对,那么我们肯定要第二种操作尽量多地减少逆序对。

考虑第二种操作 swap(i,j) 减少的逆序对数量:\(\forall k\in(i,j),h_j<h_k<h_i\),\(k\) 的个数乘二。

考虑抽象到二维平面,点坐标为 \((i,h_i)\),那么就是以 \((i,h_i)\) 为左上角,\((j,h_j)\) 为右下角的矩形内部点数量。

但这样暴力算还是 \(O(n^2\log n)\)。

看看选择的点有什么性质。

自己画画图,既然 \(i\) 为左上角,那么 \(i\) 应该是单增的,所以应该选择的是前缀最大值的点。

这时候可能有小可爱跟我一样 SB,想了好久 \(j\) 是前缀最小值还是后缀最小值。

黑色的是前缀最大值的点,红色是前缀最小值,蓝色是后缀最小值。

然后我思考了很久发现不知道选择是前缀还是后缀。

事实上图画错了!

所以显然是右端点是后缀最小值的点。

这样暴力维护也没用,找找性质,枚举右端点?可惜左端点并不单增。

考虑正难则反,让 \(k\) 去贡献每对 \((i,j)\),即每个矩形。

需要满足的是 \(i<k,h_i>h_k,j>k,h_j<h_k\),发现因为连续区间且维护的前缀最大、后缀最小都单调,因此二分找出合法区间,变成二维平面矩形加、点最大值。扫描线即可。

//swap(i,j)-> -= i<k<j ,a[i]>a[k],a[j]<a[k],a[j]<a[k]<a[i]
//二维平面(i,a[i]),矩形查

#include <bits/stdc++.h>
#define int long long
#define pb push_back
using namespace std;
#define N (int)(3e5+5)
int n,a[N],sum[N];

int lowbit(int x) {
	return x&(-x);
}
void add(int x,int v) {
	while(x<=n) sum[x]+=v,x+=lowbit(x);
}
int qry(int x) {
	int res=0; while(x) res+=sum[x],x-=lowbit(x); return res;
}

namespace zzx {
	int Ls[N*32],Rs[N*32],sum[N*32],rt[N],tot=0;
	void update(int pre,int &cur,int l,int r,int pos) {
		if(!cur) cur=++tot;
		sum[cur]=sum[pre]+1;
		if(l==r) return ;
		int mid=(l+r)>>1;
		if(pos<=mid) Rs[cur]=Rs[pre],update(Ls[pre],Ls[cur],l,mid,pos);
		else Ls[cur]=Ls[pre],update(Rs[pre],Rs[cur],mid+1,r,pos);
	}
	int query(int pre,int cur,int l,int r,int cl,int cr) {
		if(cl>cr) return 0;
		int qwq=sum[cur]-sum[pre];
		if(cl<=l&&r<=cr) return qwq;
		int mid=(l+r)>>1,res=0;
		if(cl<=mid) res=query(Ls[pre],Ls[cur],l,mid,cl,cr);
		if(cr>mid) res+=query(Rs[pre],Rs[cur],mid+1,r,cl,cr);
		return res;
	}
}
using namespace zzx;
vector<int>L,R;
struct node {
	int l,r,v;
	node() {
		
	}
	node(int nl,int nr,int nv) {
		l=nl; r=nr; v=nv;
	}
};
vector<node>p[N];

namespace XDS {
	#define ls (cur<<1)
	#define rs (ls|1)
	int mx[N<<2],tag[N<<2];
	void push_up(int cur) {
		mx[cur]=max(mx[ls],mx[rs]);
	}
	void push_down(int cur) {
		if(tag[cur]==0) return ;
		mx[ls]+=tag[cur]; mx[rs]+=tag[cur];
		tag[ls]+=tag[cur]; tag[rs]+=tag[cur];
		tag[cur]=0;
	}
	void update(int cur,int l,int r,int cl,int cr,int x) {
		if(cl<=l&&r<=cr) {
			mx[cur]+=x; tag[cur]+=x; return ;
		}
		push_down(cur);
		int mid=(l+r)>>1;
		if(cl<=mid) update(ls,l,mid,cl,cr,x);
		if(cr>mid) update(rs,mid+1,r,cl,cr,x);
		push_up(cur);
	}
	int query(int cur,int l,int r,int cl,int cr) {
		if(cl<=l&&r<=cr) {
		//	cout<<mx[cur]<<'\n';
			return mx[cur]; 
		}
		push_down(cur);
		int mid=(l+r)>>1,res=0;
		if(cl<=mid) res=query(ls,l,mid,cl,cr);
		if(cr>mid) res=max(res,query(rs,mid+1,r,cl,cr));
		return res;
	}
}
using namespace XDS;
bool vis[N];
signed main() {
	//freopen("columns9_3.in","r",stdin);
	cin.tie(0);
	std::ios::sync_with_stdio(false);
	cin>>n; int ans=0;
	for(int i=1;i<=n;i++) cin>>a[i];
	for(int i=1;i<=n;i++) {
		ans+=qry(n)-qry(a[i]);	
		add(a[i],1);
	}	
	for(int i=1;i<=n;i++) update(rt[i-1],rt[i],1,n,a[i]);
//	cout<<ans<<endl;
	int mx=0; a[0]=0;
	for(int i=1;i<=n;i++) {
		//cout<<a[i]<<" "<<a[mx]<<endl;
		if(a[i]>a[mx]) {
			mx=i; L.pb(i); vis[i]=1;//cout<<"?";
		}
	}
	a[0]=(int)(2e18); int mi=0;
	for(int i=n;i>=1;i--) {
		if(a[i]<a[mi]) {
			mi=i; R.pb(i); vis[i]=1;
		}
	}
	reverse(R.begin(),R.end());
	//cout<<L.size()<<" "<<R.size()<<'\n';
	for(int x=1;x<=n;x++) {
		if(vis[x]) continue;
		int l=0,r=L.size()-1,res=-1,xl=-1,xr=-1,yl=-1,yr=-1;
		while(l<=r) {
			int mid=(l+r)>>1;
			if(a[L[mid]]>a[x]) res=mid,r=mid-1;
			else l=mid+1;
		}
	//	if(res!=-1) cout<<res<<endl;
		if(res!=-1) {
			xl=L[res]; xr=x-1;
		}
		l=0; r=R.size()-1; res=-1;
		while(l<=r) {
			int mid=(l+r)>>1;
			if(a[R[mid]]<a[x]) res=mid,l=mid+1;
			else r=mid-1;
		}
		if(res!=-1) {
			yl=x+1; yr=R[res];
		}
		if(xl!=-1&&yl!=-1) {
			if(xl>xr||yl>yr) continue;
		//	cout<<xl<<" "<<xr<<" "<<yl<<" "<<yr<<'\n';
			p[xl].pb(node(yl,yr,1)); p[xr+1].pb(node(yl,yr,-1));
		}
	}
	int res=0;
	for(int i=1;i<=n;i++) {
		for(node x:p[i]) {
		//	cout<<x.l<<" "<<x.r<<endl;
			update(1,1,n,x.l,x.r,x.v);
		}
		res=max(res,query(1,1,n,1,n));
	}
	cout<<ans-2ll*res<<'\n';
	return 0;
}

标签:cur,LibreOJ,cl,loj,res,mid,int,最小值,Round
来源: https://www.cnblogs.com/xugangfan/p/15872260.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有