bzoj1367 [Baltic2004]sequence
1367: [Baltic2004]sequence
Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 1473 Solved: 604
[Submit][Status][Discuss]
Description
Input
Output
一个整数R
Sample Input
7
9
4
8
20
14
15
18
9
4
8
20
14
15
18
Sample Output
13
HINT
所求的Z序列为6,7,8,13,14,15,18.
R=13
分析:左偏树的应用.
减弱一下条件,如果最后求得的序列可以是非严格递增的.那么可以将原序列分为两类,一类是单调递增的,对于这一类只需要让Z序列等于t序列中的每一个数就可以了.一类是单调下降的,根据绝对值的几何意义,如果将这段序列的t全部变成它的中位数,那么答案就是最优的.那么我们只需要将t序列按照上述两种分类来分段即可.
这样会有一个问题,后面的中位数比前面的小,那么就不满足Z序列单调上升的这个条件了.这时将当前段与上一段合并,再求出新的中位数即可.如何快速求中位数是优先队列的一个经典应用,但是合并两段非常慢,那么利用可并堆,左偏树就可以了.
题目要求的是严格递增,那么在读入的时候将t序列的所有数-i即可.相当于就是一个偏移.
注意左偏树序号的问题,动态加点.
#include <cstdio> #include <cmath> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; int n,t[1000010],tot,cnt,dist[1000010],id[1000010],l[1000010],r[1000010],sizee[1000010],v[1000010],L[1000010],R[1000010]; ll ans; int hebing(int x,int y) { if (!x || !y) return x + y; if (v[x] < v[y]) swap(x,y); r[x] = hebing(r[x],y); sizee[x] = sizee[r[x]] + sizee[l[x]] + 1; if (dist[r[x]] > dist[l[x]]) swap(r[x],l[x]); dist[x] = dist[r[x]] + 1; return x; } void pop(int x) { id[x] = hebing(l[id[x]],r[id[x]]); } void newone(int x) { v[++tot] = x; sizee[tot] = 1; l[tot] = r[tot] = dist[tot] = 0; id[cnt] = tot; } void solve() { for (int i = 1; i <= n; i++) { ++cnt; newone(t[i]); L[cnt] = R[cnt] = i; while (cnt > 1 && v[id[cnt]] < v[id[cnt - 1]]) { cnt--; id[cnt] = hebing(id[cnt],id[cnt + 1]); R[cnt] = R[cnt + 1]; while (sizee[id[cnt]] * 2 > R[cnt] - L[cnt] + 2) pop(cnt); } } } int main() { scanf("%d",&n); for (int i = 1; i <= n; i++) { scanf("%d",&t[i]); t[i] -= i; } solve(); for (int i = 1; i <= cnt; i++) { int temp = v[id[i]]; for (int j = L[i]; j <= R[i]; j++) ans += abs(temp - t[j]); } printf("%lld\n",ans); return 0; }