bzoj 1367

05年的论文题,好像两篇论文里都有

可并堆维护中位数

然而论文最后的二分法没看懂QAQ网上也找不到二分的方法

所以只好用左偏树水一水了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
const int N=1000000+5;
queue<int>rubbish;
struct Heapnode{
	int l,r,v,d,sz;
	void clear(){
		l=r=v=d=sz=0;
	}
}tr[N];
int merge(int x,int y){
	if(!x||!y)return x+y;
	if(tr[x].v<tr[y].v)swap(x,y);
	tr[x].r=merge(tr[x].r,y);
	if(tr[tr[x].r].d>tr[tr[x].l].d)swap(tr[x].l,tr[x].r);
	if(!tr[x].r)tr[x].d=0;
	else tr[x].d=tr[tr[x].r].d+1;
	tr[x].sz=tr[tr[x].l].sz+tr[tr[x].r].sz+1;
	return x;
}
int pop(int x){
	int l=tr[x].l,r=tr[x].r;
	tr[x].clear();rubbish.push(x);
	return merge(l,r);
}
int sz;
int newheap(int v){
	int tmp;
	if(rubbish.empty())tmp=++sz;
	else tmp=rubbish.front(),rubbish.pop();
	tr[tmp]=(Heapnode){0,0,v,0,1};
	return tmp;
}
int push(int x,int v){
	return merge(x,newheap(v));
}
int m,s[N],l[N],r[N];
void refresh(){
	while(m>1&&tr[s[m-1]].v>=tr[s[m]].v){
		m--;
		s[m]=merge(s[m],s[m+1]);
		r[m]=r[m+1];
		if((r[m]-l[m]+2)/2<tr[s[m]].sz)
		s[m]=pop(s[m]);
	}
}
int a[N];
int iabs(int x){
	return x<0?-x:x;
}
int main(){
	//freopen("a.in","r",stdin);
	//freopen("a.out","w",stdout);
	int n;scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);a[i]-=i;
		s[++m]=newheap(a[i]);
		l[m]=r[m]=i;
		refresh();
	}
	ll ans=0;
	for(int i=1;i<=m;i++)
	for(int j=l[i];j<=r[i];j++)
	ans+=iabs(a[j]-tr[s[i]].v);
	printf("%lld\n",ans);
	return 0;
}


你可能感兴趣的:(bzoj 1367)