【BZOJ 1367】 [Baltic2004]sequence

来源:互联网 发布:最大域名注册商 编辑:程序博客网 时间:2024/06/08 16:51

1367: [Baltic2004]sequence

Time Limit: 20 Sec  Memory Limit: 64 MB
Submit: 631  Solved: 215
[Submit][Status]

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



左偏树。


详细题解(在P13)。


这个题解求的z是不减的,要求单增的话只要把a[i]减i再算即可。


很巧妙的是用左偏树来合并两个区间的中位数。


根据题解,前一个区间的中位数大于后一个区间的中位数,合并之后中位数只会变小,因此先把两个对合并(大根堆),然后把最大的一个个除去,最后剩下一半即可,最大的那个就是中位数。


一定要注意,这里的“一半”一定要向上取整!!因为如果两个区间原本都是3个,向下取整都变成1个,合并之后6个只剩下2个了。。


#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <cstdlib>#define M 1050000using namespace std;int n,a[M],root[M],l[M],r[M],w[M],tot=0,cnt=0;struct Ltree{int size,l,r,dis,v;}t[M];void read(int &tmp){tmp=0;char ch=getchar();int fu=1;for (;ch<'0'||ch>'9';ch=getchar())if (ch=='-') fu=-1;for (;ch>='0'&&ch<='9';ch=getchar())tmp=tmp*10+ch-'0';tmp*=fu;}int New_heap(int x){t[x].v=a[x];t[x].l=t[x].r=t[x].dis=0;t[x].size=1;return x;}int Merge(int x,int y){if ((!x)||(!y)) return x+y;if (t[x].v<t[y].v)swap(x,y);t[x].size+=t[y].size;t[x].r=Merge(t[x].r,y);if (t[t[x].l].dis<t[t[x].r].dis)swap(t[x].l,t[x].r);t[x].dis=t[t[x].r].dis+1;return x;}int Del(int x){return Merge(t[x].l,t[x].r);}int main(){read(n);for (int i=1;i<=n;i++)read(a[i]),a[i]-=i;tot=0;t[0].dis=-1;for (int i=1;i<=n;i++){root[++tot]=New_heap(i);w[tot]=a[i];l[tot]=r[tot]=i;while (tot>1&&w[tot-1]>w[tot]){tot--;r[tot]=r[tot+1];root[tot]=Merge(root[tot],root[tot+1]);int x=(r[tot]-l[tot]+2)/2;while (t[root[tot]].size>x)root[tot]=Del(root[tot]);w[tot]=t[root[tot]].v;}}long long ans=0LL;for (int i=1;i<=tot;i++)for (int j=l[i];j<=r[i];j++)ans+=abs(a[j]-w[i]);printf("%lld\n",ans);return 0;}



1 0
原创粉丝点击