【Loj#535】花火(線段樹,掃描線)

#【Loj#535】花火(線段樹,掃描線) ##題面 Loj ##題解 首先若是不考慮交換任意兩個數這個操做,答案就是逆序對的個數。 那麼暴力就是枚舉交換哪一個兩個數,而後用數據結構之類的東西動態維護逆序對。 可是這樣還不夠。 仔細觀察哪些點交換了纔有意義。 假設交換的位置是$l,r$ 首先必須有$h[l]\gt h[r]$,這個很顯然,若是把一個更大的數換到了前面顯然不優。 其次,$l$必須是前綴的最大值。 若是$l$不是前綴最大值,那麼存在一個位置$i$知足$h[i]\gt h[l]\gt h[r]$ 那麼直接交換$i,r$顯然更優。 同理,$r$必須是後綴的最小值。 那麼,首先把全部的前綴最大值和後綴最小值預處理出來。 每次交換的時候,咱們發現減小的逆序對數量就是 $l<i<r,h[l]>h[i]>h[r]$的全部$i$的個數。 發現這就是一個二維數點,用掃描線解決便可。ios

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 333333
#define lson (now<<1)
#define rson (now<<1|1)
inline int read()
{
    RG int x=0,t=1;RG char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
ll ans,now;
int n,a[MAX],cnt;
int st1[MAX],st2[MAX],top1,top2;
bool ins[MAX];
struct Node{int y,l,r,opt;}p[MAX<<1];
bool operator<(Node a,Node b)
{
	if(a.y!=b.y)return a.y<b.y;
	return a.opt<b.opt;
}
int binary1(int x)
{
	int l=1,r=top1,ret=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(a[st1[mid]]>a[x])ret=mid,r=mid-1;
		else l=mid+1;
	}
	return st1[ret];
}
int binary2(int x)
{
	int l=1,r=top2,ret=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(a[st2[mid]]<a[x])ret=mid,r=mid-1;
		else l=mid+1;
	}
	return st2[ret];
}
struct SegNode{int mx,tag;}t[MAX<<2];
void Modify(int now,int l,int r,int L,int R,int w)
{
	if(L<=l&&r<=R){t[now].mx+=w;t[now].tag+=w;return;}
	int mid=(l+r)>>1;
	if(L<=mid)Modify(lson,l,mid,L,R,w);
	if(R>mid)Modify(rson,mid+1,r,L,R,w);
	t[now].mx=max(t[lson].mx,t[rson].mx)+t[now].tag;
}
int c[MAX];
int lb(int x){return x&(-x);}
void add(int x){while(x<=n)++c[x],x+=lb(x);}
int getsum(int x){int ret=0;while(x)ret+=c[x],x-=lb(x);return ret;}
int main()
{
	//freopen("hanabi.in","r",stdin);
	//freopen("hanabi.out","w",stdout);
	n=read();
	for(int i=1;i<=n;++i)a[i]=read();
	for(int i=1;i<=n;++i)if(i==1||a[i]>a[st1[top1]])st1[++top1]=i,ins[i]=true;
	for(int i=n;i>=1;--i)if(i==n||a[i]<a[st2[top2]])st2[++top2]=i,ins[i]=true;
	for(int i=1;i<=n;++i)
		if(!ins[i])
		{
			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].l,p[i].r,p[i].opt);
		if(p[i].y!=p[i+1].y)ans=max(ans,1ll*t[1].mx);
	}
	ans<<=1;ans*=-1;
	for(int i=1;i<=n;++i)add(a[i]),ans+=i-getsum(a[i]);
	printf("%lld\n",ans);
	return 0;
}
相關文章
相關標籤/搜索