标签:
【题目大意】
给定一个序列t1,t2,...,tn ,求一个递增序列z1<z2<...<zn , 使得R=|t1−z1|+|t2−z2|+...+|tn−zn| 的值最小。本题中,我们只需要求出这个最小的R值。
【思路】
-这个比加延迟标记的左偏树调试得还久……WA到死……
如果ti是递增的,我们只需要取zi=ti;
如果ti是递减的,我们只需要取ti的中位数。
所以我们将ti分割成若干个区间,维护每个区间的中位数。对于[L,R]的区间,我们存放[L,(L+R)/2]在堆中。具体如下操作:
(1)加入ti,将它作为一个单独的区间。
(2)比较前一个区间的中位数(即当前栈顶的最大值)和当前区间的中位数,如果前者小于后者,就将后者压入栈中。否则将前者弹出,和后者合并。注意的是如果两个区间的大小均为奇数(注意这里说的是区间大小,即L-R+1,而不是维护中位数的堆的大小),比如3和5合并,我们只需要存4个数字,而直接合并堆中存了5个,所以弹出堆顶。
(3)把合并后的堆作为当前区间,继续操作。
某种意义上的贪心思想。
我用的是左偏树,在左偏树里同时记录了L、R、size。
不过这样操作只会得到不下降,而不是递增。据说一开始输入t[i]时,t[i]-=i即可,没有会到意思orz
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stack> 6 #include<cmath> 7 using namespace std; 8 const int MAXN=1000000+50; 9 typedef long long ll; 10 struct node 11 { 12 int key,dis,size; 13 int lson,rson,father; 14 int L,R; 15 16 }ltree[MAXN]; 17 int n,z[MAXN]; 18 stack<int> S; 19 20 void pushup(int x) 21 { 22 int l=ltree[x].lson,r=ltree[x].rson; 23 ltree[x].size=1+ltree[l].size+ltree[r].size; 24 } 25 26 void build(int rt,int x) 27 { 28 ltree[rt].key=x; 29 ltree[rt].dis=(rt==0)?-1:0; 30 ltree[rt].size=(rt==0)?0:1; 31 //不要忘了当Rt=0的时候size为0 32 ltree[rt].lson=ltree[rt].rson=0; 33 ltree[rt].father=ltree[rt].L=ltree[rt].R=rt; 34 } 35 36 int merge(int x,int y) 37 { 38 if (x==0 || y==0) return (x+y); 39 if (ltree[x].key<ltree[y].key) swap(x,y); 40 ltree[x].L=min(ltree[x].L,ltree[y].L); 41 ltree[x].R=max(ltree[x].R,ltree[y].R); 42 ltree[x].rson=merge(ltree[x].rson,y); 43 int &l=ltree[x].lson,&r=ltree[x].rson; 44 if (ltree[l].dis<ltree[r].dis) swap(l,r); 45 if (r==0) ltree[x].dis=0; 46 else ltree[x].dis=ltree[r].dis+1; 47 pushup(x); 48 return x; 49 } 50 51 int del(int rt) 52 { 53 int l=ltree[rt].lson,r=ltree[rt].rson; 54 ltree[rt].dis=0; 55 ltree[rt].size=1; 56 ltree[rt].lson=ltree[rt].rson=0; 57 int ret=merge(l,r); 58 ltree[ret].L=ltree[rt].L; 59 ltree[ret].R=ltree[rt].R; 60 return ret; 61 } 62 63 void init() 64 { 65 scanf("%d",&n); 66 for (int i=1;i<=n;i++) scanf("%d",&z[i]),z[i]-=i; 67 for (int i=1;i<=n;i++) build(i,z[i]); 68 build(0,0); 69 } 70 71 void solve() 72 { 73 int before=z[1]; 74 S.push(1); 75 for (int i=2;i<=n;i++) 76 { 77 int now=i; 78 while (!S.empty()) 79 { 80 int tail=S.top(); 81 if (ltree[now].key<ltree[tail].key) 82 { 83 S.pop(); 84 int tmp=merge(tail,now); 85 now=tmp; 86 while (ltree[now].size*2>(ltree[now].R-ltree[now].L+2)) now=del(now); 87 //不要忘记了这里是ltree[now].R-ltree[now].L+2,一开始写成了+1 88 if (S.empty()) 89 { 90 S.push(now); 91 break; 92 } 93 } 94 else 95 { 96 S.push(now); 97 break; 98 } 99 } 100 } 101 ll ans=0; 102 while (!S.empty()) 103 { 104 int now=S.top();S.pop(); 105 for (int i=ltree[now].L;i<=ltree[now].R;i++) ans+=abs(z[i]-ltree[now].key); 106 } 107 printf("%lld",ans); 108 } 109 110 int main() 111 { 112 init(); 113 solve(); 114 return 0; 115 }
【左偏树+贪心】BZOJ1367-[Baltic2004]sequence
标签:
原文地址:http://www.cnblogs.com/iiyiyi/p/5836427.html