【BZOJ 1367】 [Baltic2004]sequence 可并堆

来源:互联网 发布:淘宝蜂蜜类目怎么选择 编辑:程序博客网 时间:2024/06/08 15:10

对于t1<t2<t3显然只要取zi==ti就可以了

那么对于t1>t2>t3.....为了方便.不考虑递增,只考虑不下降,画出每一个数字的坐标(i , t[i])那么问题就是找到一条水平直线到所有点的距离和最小,先任意画一条直线,然后考虑上下移动直线是否会使答案更优,显然直线向上移动一格的代价变换是  : 在直线下方的点数- 在直线上方的点数,这样就可以证明贪心的正确性了,即在中位数的时候最优。

然后就可以按值分段处理了,怎么用可并堆维护中位数呢?只在堆中维护n/2个数字,那么每一次查询堆顶就行了

最后如何处理递增呢,很简单另a[i]=a[i]-i就可以转化成不下降了

#include<cstdio>#include<cstring>#include<iostream>#include<cmath>#include<cstdlib> #define maxn 1000021#define LL long longusing namespace std;void read(int& x){x=0;char c=getchar();for(;c>'9'||c<'0';c=getchar());for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';}int n,a[maxn],rt[maxn],now,l[maxn],r[maxn];LL ans;struct Ltree{int v[maxn],d[maxn],ls[maxn],rs[maxn];int sz[maxn],tot;int merge(int x,int y){if(x==0 || y==0)return x+y;if(v[x]<v[y])swap(x,y);rs[x]=merge(rs[x],y);if(d[rs[x]]>d[ls[x]])swap(ls[x],rs[x]);d[x]=d[rs[x]]+1;sz[x]=sz[ls[x]]+sz[rs[x]]+1;return x;}void pop(int& x){x=merge(ls[x],rs[x]);}int size(int x){return sz[x];}int top(int x){return v[x];}void push(int& x,int y){x=++tot;v[x]=y,d[x]=1,sz[x]=1;}}q;int main(){read(n);for(int i=1;i<=n;i++)read(a[i]),a[i]-=i;for(int x,y,i=1;i<=n;i++){x=a[i];now++;l[now]=r[now]=i;q.push(rt[now],x);while(now>1&&q.top(rt[now-1])>q.top(rt[now])){now--;rt[now]=q.merge(rt[now],rt[now+1]);r[now]=r[now+1];y=r[now]-l[now]+1;while(q.size(rt[now])*2 > y+1)q.pop(rt[now]); }}for(int x,i=1;i<=now;i++){x=q.top(rt[i]);for(int j=l[i];j<=r[i];j++)ans+=abs(x-a[j]);}cout<<ans;return 0;}


0 0
原创粉丝点击