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\n",ans); 40 return 0; 41 }
1367: [Baltic2004]sequence
Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 953 Solved: 362
[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