您的位置:首页 > 产品设计 > UI/UE

bzoj 1367: [Baltic2004]sequence 左偏树

2018-02-06 07:54 561 查看

bzoj 1367: [Baltic2004]sequence

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

分析

贪心可知,本题就是要维护若干段递增中位数的区间。

证明可以看:左偏树的特点及其应用

然后每次左偏树维护本区间小的那一半的数,这样堆顶就是中位数。判断+合并即可。

代码

/**************************************************************
Problem: 1367
User: 2014lvzelong
Language: C++
Result: Accepted
Time:7992 ms
Memory:35664 kb
****************************************************************/

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
const int N = 1100000;
int read() {
char ch = getchar();int x = 0, f = 1;
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 h
, siz
, w
, ls
, rs
, L
, R
, rt
, n;
void Update(int p) {
h[p] = h[rs[p]] + 1;
siz[p] = siz[ls[p]] + siz[rs[p]] + 1;
}
int Merge(int u, int v) {
if(!u || ! v) return u +
4000
v;
if(w[u] < w[v]) swap(u, v);
rs[u] = Merge(rs[u], v);
if(h[rs[u]] > h[ls[u]]) swap(ls[u], rs[u]);
Update(u); return u;
}

int main() {
n = read(); h[0] = -1;
for(int i = 1;i <= n; ++i) w[i] = read() - i;
int sz = 0;
for(int i = 1;i <= n; ++i) {
siz[rt[++sz] = L[sz] = R[sz] = i] = 1;
while(sz > 1 && w[rt[sz]] < w[rt[sz - 1]]) {
rt[--sz] = Merge(rt[sz], rt[sz + 1]); R[sz] = R[sz + 1];
while((siz[rt[sz]] << 1) > R[sz] - L[sz] + 2)
rt[sz] = Merge(ls[rt[sz]], rs[rt[sz]]);
}
}
long long ans = 0;
for(int i = 1;i <= sz; ++i) {
for(int j = L[i];j <= R[i]; ++j)
ans += abs(w[j] - w[rt[i]]);
}
printf("%lld\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: