BZOJ1367: [Baltic2004]sequence(左偏树)

Description

Input

Output

一个整数R

Sample Input

7
9
4
8
20
14
15
18

Sample Output

13

解题思路:

有趣的数学题。
首先确定序列的构造方式。
要求差的绝对值最小,并且递增。
这肯定是照着A序列做的,那么很显然的结论:
若A是递增的,那么Z一定是A序列。
若A是平的,那么Z一定是公差为1的等差数列,中位数为A中的唯一值。
那么就发现了,若保证其非减的话是非常容易得到最优解的。
不断合并中位数即可,原理就是绝对值函数那个好几截棍。(数学课要好好听)
合并中位数可以用可并堆,因为其定义为排名在中间的数,不是不断弹就好了。
代码:
 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define lll l[x].ls
 5 #define rrr l[x].rs
 6 typedef long long lnt;
 7 struct lhnt{
 8     int ls;
 9     int rs;
10     int fa;
11     int dis;
12     lnt val;
13 }l[1000000];
14 struct seg{
15     int l;
16     int r;
17     int wgt;
18     int root;
19     lnt val;
20     seg(){};
21     seg(int x,lnt y)
22     {
23         l=r=root=x;
24         wgt=1;
25         val=y;
26     }
27 }st[1000000];
28 int top;
29 int n;
30 lnt a[1000000];
31 lnt b[1000000];
32 int merge(int x,int y)
33 {
34     if(!x||!y)
35         return x+y;
36     if(l[x].val<l[y].val)
37         std::swap(x,y);
38     rrr=merge(rrr,y);
39     l[rrr].fa=x;
40     if(l[rrr].dis>l[lll].dis)
41         std::swap(lll,rrr);
42     l[x].dis=l[rrr].dis+1;
43     return x;
44 }
45 int pop(int x)
46 {
47     return merge(lll,rrr);
48 }
49 int main()
50 {
51 //    freopen("a.in","r",stdin);
52 //    freopen("my.out","w",stdout);
53     scanf("%d",&n);
54     for(int i=1;i<=n;i++)
55     {
56         scanf("%lld",&a[i]),a[i]-=i;
57         st[++top]=seg(i,a[i]);
58         l[i].val=a[i];
59         while(top>1&&st[top].val<st[top-1].val)
60         {
61             int x=top-1,y=top;
62             top--;
63             st[x].root=merge(st[x].root,st[y].root);
64             st[x].wgt+=st[y].wgt;
65             st[x].r=st[y].r;
66             while(st[x].wgt>((st[x].r-st[x].l+2)/2))
67             {
68                 st[x].root=pop(st[x].root);
69                 st[x].wgt--;
70             }
71             st[top].val=l[st[top].root].val;
72         }
73     }
74     lnt ans=0;
75     for(int i=1;i<=top;i++)
76         for(int j=st[i].l;j<=st[i].r;j++)
77         {
78             b[j]=st[i].val;
79             ans+=std::abs(a[j]-b[j]);
80         }
81     printf("%lld\n",ans);
82     return 0;
83 }

 

 
posted @ 2019-01-08 15:53  Unstoppable728  阅读(266)  评论(0编辑  收藏  举报