昨晚的比赛题。(像我这种蒟蒻只能打打div2)

题意

  给你$n$个物品,每一个物品$i$,有一个权值$w_i$和一个位置$a_i$,定义移动一个物品$i$到位置$t$的代价为$w_i * \left |a_i - t  \right |$,要求你写一个数据结构支持以下两种操作:

    1、修改一个物品的权值

    2、查询把一个区间内全部移到相邻的位置的最小值。

  举个栗子:如果要把$[l, r]$移到相邻的位置,就是对于$\forall i \in [l, r]$,要有$pos_i = x + i - l\ (1 \leq x \leq n - (r - l))$,然后要确定这个$x$使移动的总代价最小,最后要求这个最小的代价对$1e9 + 7$取模的结果,每次询问独立。

  注意:要先使总代价最小然后再取模,而不是取模后最小。

  保证给出的$a_i$递增。

两个原题:

  一个简单题:

    我们有很经典的货仓选址的模型,就是在直线上有$n$个点,每一个点$i$有一个位置$pos_i$,每一个点有一个货物。定义运输货物的代价是移动的距离。现在要在直线上选择一个点建立货仓,要把所有的货物都运到这个点,要求使使代价最小,求这个最小代价。

    很简单吧,中位数。

    抄一段lyd书上的证明:先把所有的点按照$pos_i$排序,假设货仓建在$X$,左侧的点有$P$个,右侧的点有$Q$个。如果$P < Q$,那么把$X$往右移动会使答案变优,同理当$P > Q$使把$X$向左移动会使答案变优,所有最优解会在$P == Q$的地方产生。

    再抄一句:当$n$是偶数的时候,这时$pos_{\frac{n}{2}}$和$pos_{\frac{n + 1}{2}}$中的点都可以是最优解。

  稍微强化板:

    现在每一个货仓$i$里有$w_i$个货物。

    排序后,找到第一个$X$,使$\sum_{i = 1}^{X}a_i \geq \sum_{i = X + 1}^{n}a_i$,$X$就是最优解。

    这个东西叫做带权中位数

    丢一个百度百科的链接,里面有证明。                  传送门

    我自己把不严谨的证明在这里再写一遍:

      假设最优答案在$T$取到,那么有(唔,这里$a_i$代表权值):

          $\sum_{i = 1}^{n}a_i  *dis(i, T) \leq \sum_{i = 1}^{n}a_i * dis(i, T + 1)$

      变形一下:

          $\sum_{i = 1}^{T - 1}a_i  *dis(i, T) + \sum_{i = T + 1}^{n}a_i  *dis(i, T)  + a_{T + 1} * dis(T, T + 1)\leq \sum_{i = 1}^{T}a_i  *dis(i, T + 1) + \sum_{i = T + 2}^{n}a_i  *dis(i, T + 1)  + a_T * dis(T, T + 1)$

      

      发现$T$左边的点走到$T + 1$与走到$T$比,多走了$dis(T, T + 1)$,而右边的点则少走了$dis(T, T + 1)$。

      消掉一模一样的东西就得到了: $\sum_{i = 1}^{T}a_i \geq \sum_{i = T + 1}^{n}a_i$。

      把$T$和$T - 1$代进去也是一样的结果。

回到这题

  那么这题要求移到相邻的位置,可以理解为先移到同一个位置然后移回来,相对移动不变,我们只要找到这个带权中位数的位置,就能得到最优解了。

  带上修改,我们可以用两个树状数组来维护,一个维护$\sum_{i = 1}^{n}w_i$,另一个维护$\sum_{i = 1}^{n}w_i*(a_i - i)$,询问的时候先二分一下找到带权中位数的位置$pos$,然后对于$pos$左边的点向右移,对于$pos$右边的点向左移,就可以计算出答案了。

  时间复杂度$O(nlog^2{n})$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 2e5 + ;
const ll P = 1e9 + ; int n, qn;
ll a[N], w[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for(; ch > ''|| ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} namespace BitSum {
ll s[N]; #define lowbit(p) (p & (-p)) inline void modify(int p, ll v) {
for(; p <= n; p += lowbit(p))
s[p] += v;
} inline ll query(int p) {
ll res = 0LL;
for(; p > ; p -= lowbit(p))
res += s[p];
return res;
} inline ll getSum(int l, int r) {
if(r < l) return 0LL;
return query(r) - query(l - );
} } namespace BitMul {
ll s[N]; #define lowbit(p) (p & (-p)) inline void modify(int p, ll v) {
v %= P;
for(; p <= n; p += lowbit(p))
(s[p] = s[p] + v + P) %= P;
} inline ll query(int p) {
ll res = 0LL;
for(; p > ; p -= lowbit(p))
(res += s[p]) %= P;
return res;
} inline ll getSum(int l, int r) {
return (query(r) - query(l - ) + P) % P;
} } inline int getPos(int x, int y) {
int ln = x, rn = y, mid, res;
for(; ln <= rn; ) {
mid = (ln + rn) / ;
if(BitSum :: getSum(x, mid) >= BitSum :: getSum(mid + , y))
res = mid, rn = mid - ;
else ln = mid + ;
}
return res;
} inline ll abs(ll x) {
return x > ? x : -x;
} inline ll max(ll x, ll y) {
return x > y ? x : y;
} inline ll min(ll x, ll y) {
return x > y ? y : x;
} inline void solve(int x, int y) {
if(x == y) {
puts("");
return;
}
int pos = getPos(x, y);
/* ll res = BitMul :: getSum(x, y); //d1 = 0LL, d2 = 0LL;
d1 = (d1 - (BitSum :: getSum(pos, y) % P) * 1LL * abs(a[pos] - pos) % P + P) % P;
d1 = (d1 + (BitSum :: getSum(x, pos - 1) % P) * 1LL * abs(a[pos] - pos) % P + P) % P;
d2 = (d2 - (BitSum :: getSum(pos + 1, y) % P) * 1LL * abs(a[pos] - pos) % P + P) % P;
d2 = (d2 + (BitSum :: getSum(x, pos) % P) * 1LL * abs(a[pos] - pos) % P + P) % P;
ll d = 0LL;
d = (d - (BitSum :: getSum(pos, y) % P) * 1LL * abs(a[pos] - pos) % P + P) % P;
d = (d + (BitSum :: getSum(x, pos - 1) % P) * 1LL * abs(a[pos] - pos) % P + P) % P; */ ll res = 0LL;
res = (-BitMul :: getSum(x, pos) + (BitSum :: getSum(x, pos) % P) * abs(a[pos] - pos) % P + P) % P;
res = (res - (BitSum :: getSum(pos, y)) % P * abs(a[pos] - pos) % P + BitMul :: getSum(pos, y) + P) % P; // printf("%lld\n", (res + d + P) % P);
printf("%lld\n", res);
} int main() {
read(n), read(qn);
for(int i = ; i <= n; i++) read(a[i]);
for(int i = ; i <= n; i++) {
read(w[i]);
BitMul :: modify(i, w[i] * (a[i] - i));
BitSum :: modify(i, w[i]);
} for(int x, y; qn--; ) {
read(x), read(y);
if(x < ) {
x = -x;
BitSum :: modify(x, -w[x]);
BitMul :: modify(x, -1LL * w[x] * (a[x] - x));
w[x] = 1LL * y;
BitSum :: modify(x, w[x]);
BitMul :: modify(x, 1LL * w[x] * (a[x] - x));
} else solve(x, y);
} /* for(int i = 1; i <= n; i++)
printf("%lld ", BitSum :: getSum(i, i)); */ return ;
}

CF1030F Putting Boxes Together的更多相关文章

  1. 洛谷CF1030F Putting Boxes Together(树状数组)

    题意: 现在有n个物品,第i个物品他的位置在a[i],他的重量为w[i].每一个物品移动一步的代价为他的w[i].目前有2种操作: 1. x y 将第x的物品的重量改为y 2.l r 将编号在 [ l ...

  2. Codeforces 1053 C - Putting Boxes Together

    C - Putting Boxes Together 思路: 求带权中位数 用树状数组维护修改 代码: #pragma GCC optimize(2) #pragma GCC optimize(3) ...

  3. CodeForces 1058 F Putting Boxes Together 树状数组,带权中位数

    Putting Boxes Together 题意: 现在有n个物品,第i个物品他的位置在a[i],他的重量为w[i].每一个物品移动一步的代价为他的w[i].目前有2种操作: 1. x y 将第x的 ...

  4. Codeforces 1053C Putting Boxes Together 树状数组

    原文链接https://www.cnblogs.com/zhouzhendong/p/CF1053C.html 题目传送门 - CF1053C 题意 有 $n$ 个物品,第 $i$ 个物品在位置 $a ...

  5. Putting Boxes Together CodeForces - 1030F (带权中位数)

    #include <iostream> #include <algorithm> #include <cstdio> #include <math.h> ...

  6. 2018.09.24 codeforces 1053C. Putting Boxes Together(线段树)

    传送门 就是让你维护动态的区间带权中位数. 然而昨晚比赛时并没有调出来. 想找到带权中位数的中点可以二分(也可以直接在线段树上找). 也就是二分出第一个断点,使得断点左边的和恰好大于或等于断点右边的和 ...

  7. [CF1053C]Putting Boxes Together(线段树)

    http://codeforces.com/blog/entry/62013 两个结论: 1.一定有一个箱子不用动. 2.不动的箱子一定是加权前缀和为S/2的那个. 1显然,2由1易得. 于是问题变为 ...

  8. [Codeforces 1053C] Putting Boxes Together

    Link: Codeforces 1053C 传送门 Solution: 先推出一个结论: 最后必有一个点不动且其为权值上最中间的一个点 证明用反证证出如果不在中间的点必有一段能用代价少的替代多的 这 ...

  9. Technocup 2019 - Elimination Round 1

    http://codeforces.com/contest/1030 B. Vasya and Cornfield 判断点是否在矩形内(包括边界) 把每条边转化为一个不等式 public static ...

随机推荐

  1. 在ios7中使用zxing

    ZXing(Github镜像地址)是一个开源的条码生成和扫描库(开源协议为Apache2.0).它不但支持众多的条码格式,而且有各种语言的实现版本,它支持的语言包括:Java, C++, C#, Ob ...

  2. 如何显示PHP运行错误

    在运行文件的最前面加两行代码: error_reporting(E_ALL); ini_set('display_errors', '1'); 这样调试起来就方便多了

  3. 非root用户 如何将cscope安装到指定目录,vim74安装

    随着Linux的普及,使用Linux进行软件开发的人也越来越多.而大多数公司都采用这种方式:提供一台高性能的中央服务器做为开发编译服务器,每个人登录这台服务器进行开发编译.在这种情况下,用户通常没有r ...

  4. map的内存分配机制分析

    该程序演示了map在形成的时候对内存的操作和分配. 因为自己对平衡二叉树的创建细节理解不够,还不太明白程序所显示的日志.等我明白了,再来修改这个文档. /* 功能说明: map的内存分配机制分析. 代 ...

  5. WPF之X名称空间学习

    WPF的X名称空间都有什么呢?首先,盗用张图来说明: 我将就图表中的内容进行总结: 1.x:Array具有一个Iteams属性,它能暴漏一个ArratList实例,ArratList实例的内部成员类型 ...

  6. Investment(完全背包)

    个人心得:炸了炸了,这背包什么的脑阔痛. 完全背包什么鬼咯,状态正向转移与01背包正好相反. 二维数组的状态转移. 一维数组的优化,注意正向覆盖. 本题中的思想 ;y<=year;y++){ ; ...

  7. LeetCode Reverse String II

    原题链接在这里:https://leetcode.com/problems/reverse-string-ii/#/description 题目: Given a string and an inte ...

  8. CH5702 Count The Repetitions[倍增dp]

    http://contest-hunter.org:83/contest/0x50%E3%80%8C%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E3%80%8D%E4%B ...

  9. UI及物体渲染顺序

    1.决定UI渲染在所有物体前,ZTest Always,Canvas中的RenderMode影响该值. 2.都是ZTest Always 时影响覆盖的因素: 父子及先后关系: 渲染队列: sortin ...

  10. Java处理乱码问题

    中文乱码分为GET乱码和POST乱码 GET乱码在Tomcat中配置编码 <Connector port="8080" protocol="HTTP/1.1&quo ...