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;
    }
    
  • 相关阅读:
    SQL-排名函数
    SQL-简单查询
    SQL-判断表是否存在
    HDU1557权利选举
    Bresenham画直线,任意斜率
    LCS最长公共子序列HDU1159
    zoj1276矩阵连乘dp
    OJ的文件流操作
    dp题目
    翻纸牌 高校俱乐部 英雄会 csdn
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9290228.html
Copyright © 2011-2022 走看看