CF1030F Putting Boxes Together
Posted huyufeifei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CF1030F Putting Boxes Together相关的知识,希望对你有一定的参考价值。
CF1030F - Putting Boxes Together
题意:给定数轴上的n个物体,你要把第l个物体到第r个物体之间的所有物体挪到挨在一起,使得总消耗最小。带修。消耗是重量乘距离。
解:就是带权中位数。有个结论是一定有一个物体不动。还有一个结论是不动的物体左右两边权值和之差最小。
于是我们先找到那个不动位置,然后计算把别的挪过去的消耗。
找它就先查权值和,先+1然后除以2,然后找到那个位置。
计算消耗就维护一个全挪到最左最右的消耗,一个从最左最右散开的消耗,然后跟sum加加减减一下。不需要在线段树上维护很多东西。
1 /** CF 1030F */ 2 #include <bits/stdc++.h> 3 4 typedef long long LL; 5 6 const int N = 200010, MO = 1e9 + 7; 7 8 LL sum[N << 2], tr[N << 2], tl[N << 2], w[N]; 9 int X[N], xx, a[N], n; 10 11 inline void Add(int &a, const int &b) 12 a += b; 13 if(a >= MO) a -= MO; 14 if(a < 0) a += MO; 15 return; 16 17 18 struct TA 19 int ta[N]; 20 inline void add(int i, int v) 21 for(; i <= n; i += i & (-i)) 22 Add(ta[i], v); 23 24 return; 25 26 inline int ask(int i) 27 int ans = 0; 28 for(; i; i -= i & (-i)) 29 Add(ans, ta[i]); 30 31 return ans; 32 33 inline int getSum(int l, int r) 34 return (ask(r) - ask(l - 1) + MO) % MO; 35 36 ta1, ta2, ta3, ta4; 37 38 inline void pushup(int l, int r, int o) 39 int ls = o << 1, rs = ls | 1, mid = (l + r) >> 1; 40 sum[o] = sum[ls] + sum[rs]; 41 tl[o] = tl[ls] + tl[rs] + sum[rs] * (X[mid + 1] - X[l] - (mid - l + 1)); 42 tr[o] = tr[ls] + tr[rs] + sum[ls] * (X[r] - X[mid] - (r - mid)); 43 return; 44 45 46 void build(int l, int r, int o) 47 if(l == r) 48 sum[o] = w[r]; 49 return; 50 51 int mid = (l + r) >> 1; 52 build(l, mid, o << 1); 53 build(mid + 1, r, o << 1 | 1); 54 pushup(l, r, o); 55 return; 56 57 58 void change(int p, int v, int l, int r, int o) 59 if(l == r) 60 sum[o] = v; 61 return; 62 63 int mid = (l + r) >> 1; 64 if(p <= mid) 65 change(p, v, l, mid, o << 1); 66 67 else 68 change(p, v, mid + 1, r, o << 1 | 1); 69 70 pushup(l, r, o); 71 return; 72 73 74 LL getSum(int L, int R, int l, int r, int o) 75 if(L <= l && r <= R) 76 return sum[o]; 77 78 int mid = (l + r) >> 1; 79 LL ans = 0; 80 if(L <= mid) 81 ans = getSum(L, R, l, mid, o << 1); 82 83 if(mid < R) 84 ans += getSum(L, R, mid + 1, r, o << 1 | 1); 85 86 return ans; 87 88 89 int getPos(LL k, int l, int r ,int o) 90 if(l == r) 91 return r; 92 93 int mid = (l + r) >> 1; 94 if(k <= sum[o << 1]) 95 return getPos(k, l, mid, o << 1); 96 97 else 98 return getPos(k - sum[o << 1], mid + 1, r, o << 1 | 1); 99 100 101 102 int Ask(int x, int y) 103 LL sum = getSum(x, y, 1, n, 1); 104 LL sum2 = 0; 105 if(x > 1) sum2 = getSum(1, x - 1, 1, n, 1); 106 LL delta = sum2 + ((sum + 1) >> 1); 107 int p = getPos(delta, 1, n, 1); 108 int ans = 0; 109 if(x < p) 110 LL Sum = getSum(x, p - 1, 1, n, 1) % MO; 111 Add(ans, ((LL)ta3.getSum(x, p - 1) - ta4.getSum(x, p - 1) - Sum * (X[n] - X[p] - (n - p)) % MO) % MO); 112 113 if(p < y) 114 LL Sum = getSum(p + 1, y, 1, n, 1) % MO; 115 Add(ans, ((LL)ta1.getSum(p + 1, y) - ta2.getSum(p + 1, y) - Sum * (X[p] - X[1] - (p - 1))) % MO); 116 //printf("%d %d %lld * %d\n", ta1.getSum(p + 1, y), ta2.getSum(p + 1, y), Sum, (X[p] - X[1] - (p - 1))); 117 118 return ans; 119 120 121 int main() 122 123 int q; 124 scanf("%d%d", &n, &q); 125 for(int i = 1; i <= n; i++) 126 scanf("%d", &X[i]); 127 128 for(int i = 1; i <= n; i++) 129 scanf("%lld", &w[i]); 130 131 build(1, n, 1); 132 for(int i = 1; i <= n; i++) 133 LL c = w[i]; 134 ta1.add(i, c * (X[i] - X[1]) % MO); 135 ta2.add(i, c * (i - 1) % MO); 136 ta3.add(i, c * (X[n] - X[i]) % MO); 137 ta4.add(i, c * (n - i) % MO); 138 139 140 int x, y; 141 for(int i = 1; i <= q; i++) 142 scanf("%d%d", &x, &y); 143 if(x < 0) 144 x = -x; 145 change(x, y, 1, n, 1); 146 int dt = (y - w[x] + MO) % MO; 147 ta1.add(x, (LL)dt * (X[x] - X[1]) % MO); 148 ta2.add(x, (LL)dt * (x - 1) % MO); 149 ta3.add(x, (LL)dt * (X[n] - X[x]) % MO); 150 ta4.add(x, (LL)dt * (n - x) % MO); 151 w[x] = y; 152 153 else 154 int ans = Ask(x, y); 155 printf("%d\n", ans); 156 157 158 159 return 0; 160
以上是关于CF1030F Putting Boxes Together的主要内容,如果未能解决你的问题,请参考以下文章
Putting Boxes Together CodeForces - 1030F (带权中位数)
codeforces round 512 F. Putting Boxes Together 树状数组维护区间加权平均数