昨晚的比赛题。(像我这种蒟蒻只能打打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. L123

    My heart, the bird of the wilderness, has found its sky in your eyes. 我的心是旷野的鸟,在你的双眼中找到了天空.His main ...

  2. Redis 高可用及分片集群,说了你也不懂

    Redis 简介 Memcached: 优点:高性能读写.单一数据类型.支持客户端式分布式集群.一致性hash 多核结构.多线程读写性能高. 缺点:无持久化.节点故障可能出现缓存穿透.分布式需要客户端 ...

  3. 浅学soap--------4

    引入nusoap Service.php //运行该文件,在网页中wsdl点击,可浏览生成的wsdl代码;网页提供注册的方法 <?php require_once ("nusoap/n ...

  4. itunesconnect如何提交被决绝过了的相同版本号

    遇到一次审核被拒,打算再次提交时,不想改变版本号,可以在xcode里把build版本号后面几个.1,比如version上次被拒时是1.1.3,build也是1.1.3,这次送审时version不变,b ...

  5. [Luogu3674]小清新人渣的本愿

    luogu 题意 给你一个序列a,长度为n,有m次操作,每次询问一个区间是否可以选出两个数它们的差为x,或者询问一个区间是否可以选出两个数它们的和为x,或者询问一个区间是否可以选出两个数它们的乘积为x ...

  6. C++对C语言的拓展(5)—— 函数重载和函数指针结合

    1.函数指针的介绍 函数指针指向某种特定类型,函数的类型由其参数及返回类型共同决定,与函数名无关.举例如下: int add(int nLeft,int nRight);//函数定义 该函数类型为in ...

  7. BZOJ4303:数列

    浅谈\(K-D\) \(Tree\):https://www.cnblogs.com/AKMer/p/10387266.html 题目传送门:https://lydsy.com/JudgeOnline ...

  8. laravel 接收json串

    在做项目的时候发现 用平时的$request->all() 无法获取到请求值 然后这样解决了 但是还是不知道原因 学习源头: http://www.cnblogs.com/anjuncc/p/5 ...

  9. IIS:template

    ylbtech-IIS: 1.返回顶部   2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返回顶部   8.返回顶部   9.返回顶部   10.返 ...

  10. 问题:C#控制台;结果:C#限制程序只能运行一個实例 (防多开)

    C# Console类的具体用法 作者: 字体:[增加 减小] 类型:转载 时间:2013-03-08 这篇文章主要介绍C# Console类的具体用法,需要的朋友可以参考下   Console.Wr ...