zoukankan      html  css  js  c++  java
  • [LOJ535]「LibreOJ Round #6」花火

    loj

    description

    给你一个排列(h_i),你需要交换任意两个位置上的数使得交换后排列的逆序对数最少。
    (n le 3 imes 10^5)

    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))构成的矩形内部的条件就是:(iin[l,x-1],jin[x+1,r])
    把点转化为矩阵,问题变成求矩形覆盖的最大值,线段树维护扫描线即可。
    复杂度(O(nlog n))

    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
    ",sum-2*ans);
    	return 0;
    }
    
  • 相关阅读:
    POJ 2236 Wireless Network(并查集)
    POJ 2010 Moo University
    POJ 3614 Sunscreen(贪心,区间单点匹配)
    POJ 2184 Cow Exhibition(背包)
    POJ 1631 Bridging signals(LIS的等价表述)
    POJ 3181 Dollar Dayz(递推,两个long long)
    POJ 3046 Ant Counting(递推,和号优化)
    POJ 3280 Cheapest Palindrome(区间dp)
    POJ 3616 Milking Time(dp)
    POJ 2385 Apple Catching(01背包)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9290228.html
Copyright © 2011-2022 走看看