【bzoj1367】[Baltic2004]sequence

2016-05-31 17:31:26

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1367

题解:http://www.cnblogs.com/rausen/p/4033724.html

说一下堆里维护的是什么。

维护的是所代表区间的中位数,这是一棵大根堆,只有序列递减时我们才会合并堆,也就是加入的数是小的,所以只会将中位数变小,弹出堆顶更新。

题目要求的是单增的序列,但我们这样求出的是不减。

一个小技巧,就是每个数在读入时减去i,这样就保证了修改后的序列不减的情况下,是原序列的单增。

而这种改变是极小的,即不会改变答案大小。

 1 #include<bits/stdc++.h>
 2 #define inf 1000000000
 3 #define ll long long
 4 #define N 1000005
 5 using namespace std;
 6 int read(){
 7   int x=0,f=1;char ch=getchar();
 8   while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
 9   while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
10   return x*f;
11 }
12 int n,tot,rt[N],v[N],dep[N],ls[N],rs[N],l[N],r[N],cnt[N],num[N];
13 int merge(int x,int y){
14   if(!x||!y)return x+y;
15   if(v[x]<v[y])swap(x,y);
16   rs[x]=merge(rs[x],y);
17   if(dep[ls[x]]<dep[rs[x]])swap(ls[x],rs[x]);
18   dep[x]=dep[rs[x]]+1;
19   return x;
20 }
21 int main(){
22   n=read();
23   for(int i=1;i<=n;i++)v[i]=read()-i;
24   for(int i=1;i<=n;i++){
25     ++tot;
26     rt[tot]=i;cnt[tot]=1;num[tot]=1;
27     l[tot]=r[tot]=i;
28     while(tot>1&&v[rt[tot]]<v[rt[tot-1]]){
29       --tot;
30       rt[tot]=merge(rt[tot],rt[tot+1]);
31       num[tot]+=num[tot+1];cnt[tot]+=cnt[tot+1];r[tot]=r[tot+1];
32       for(;cnt[tot]*2>num[tot]+1;cnt[tot]--)rt[tot]=merge(ls[rt[tot]],rs[rt[tot]]);
33     }
34   }
35   ll ans=0;
36   for(int i=1;i<=tot;i++)
37     for(int j=l[i],w=v[rt[i]];j<=r[i];j++)
38       ans+=abs(v[j]-w);
39   printf("%lld
",ans);
40   return 0;
41 }
View Code

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

原文地址:https://www.cnblogs.com/wjyi/p/5546696.html