bzoj1367【Baltic2004】sequence

来源:互联网 发布:淘宝代运营谁管钱 编辑:程序博客网 时间:2024/06/08 06:10

1367: [Baltic2004]sequence

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 953  Solved: 362
[Submit][Status][Discuss]

Description

Input

Output

一个整数R

Sample Input

7
9
4
8
20
14
15
18

Sample Output

13

HINT

所求的Z序列为6,7,8,13,14,15,18.
R=13




可并堆,思路很好

分享一篇题解:http://www.cnblogs.com/rausen/p/4033724.html

说一下如何用可并堆维护区间中位数。

维护一个大根堆,堆里的元素个数等于区间长度的一半,里面保存的数是区间中较小的一半数。那么很显然中位数就是堆顶元素。

两个区间合并的时候,把两个堆合并,并将多余的元素弹出,这样就可以维护区间中位数了。

其实维护小根堆也是可以的,区别是要维护区间中较大的一半数。

据说还有一个小技巧(表示自己没有理解这里):

这样求出来的z[i]是单调不减,并不保证单调递增。

开始的时候将每一个t[i]减去i,然后按照该方法计算z[i],这样就相当于所有z[i]都加上了i,就把不减转化成了递增。(然而这为什么是对的呢...求助大神)




#include<iostream>#include<cstdlib>#include<cstring>#include<cmath>#include<cstdio>#include<algorithm>#define F(i,j,n) for(int i=j;i<=n;i++)#define D(i,j,n) for(int i=j;i>=n;i--)#define ll long long#define N 1000005using namespace std;int n,m,tot,a[N],rt[N],l[N],r[N];ll ans;struct HEAP{int cnt,l[N],r[N],v[N],d[N],sz[N];int merge(int x,int y){if (!x||!y) return x+y;if (v[x]<v[y]) swap(x,y);r[x]=merge(r[x],y);if (d[l[x]]<d[r[x]]) swap(l[x],r[x]);d[x]=d[r[x]]+1;sz[x]=sz[l[x]]+sz[r[x]]+1;return x;}void pop(int &x){x=merge(l[x],r[x]);}int new_heap(int x){cnt++;v[cnt]=x;sz[cnt]=1;l[cnt]=r[cnt]=0;d[cnt]=1;return cnt;}}heap;inline int read(){int x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}int main(){n=read();F(i,1,n) a[i]=read()-i;F(i,1,n){tot++;rt[tot]=heap.new_heap(a[i]);l[tot]=r[tot]=i;while (tot>1&&heap.v[rt[tot-1]]>heap.v[rt[tot]]){tot--;rt[tot]=heap.merge(rt[tot],rt[tot+1]);r[tot]=r[tot+1];while (heap.sz[rt[tot]]>(r[tot]-l[tot]+2)/2) heap.pop(rt[tot]);}}F(i,1,tot){int tmp=heap.v[rt[i]];F(j,l[i],r[i]) ans+=abs(a[j]-tmp);}printf("%lld\n",ans);return 0;}


0 0
原创粉丝点击