题意:

现在有n个物品,第i个物品他的位置在a[i],他的重量为w[i]。每一个物品移动一步的代价为他的w[i]。目前有2种操作:

1. x y 将第x的物品的重量改为y

2.l r 将编号在 [ l, r ]之间的所有物品移动到一起,求最小的花费是多少。

带权中位数,学习了->这里

先来考虑一下货仓选址问题,就是一堆不带权值的数,选出一个点使得所有点到他的距离之和最小,那么肯定是选中位数最优

然后加上权值限制,这玩意儿有个学名叫做带权中位数

带权中位数为满足$\sum_{i=1}^x w_i\geq \sum_{i=x+1}^n w_i$的最大的$x$

简单证(kou)明(hu)一下为什么是对的,假设将区间内的所有数移到$x+1$的位置,那么$[1,x]$内的数全都要多走$dis[x,x+1]$的路程,而$[x+1,n]$内的数可以少走这么多路程,那么总权值的变化量就为$dis[x,x+1]*(sum_{i=1}^x w_i-\sum_{i=x+1}^n w_i)$,可以发现若上面那个不等式不成立则往右移总权值变小,也就是说答案会更优,所以只有当上面那个等式成立时才不会往右移更优。又因为这玩意儿是从左边移过来的,所以左边的都比他劣。那么它一定是最优的。

于是这个东西我们可以二分

然后我们来考虑一下原问题,发现所有的移动方案都可以等价于固定一个点不动,其他的点向它靠。那么我们设$pos$为最优的点,然后用和上面的方法一样考虑可以发现当$pos$为带权中位数时答案最优。所以我们可以直接二分出$pos$

现在的问题就是如何快速计算总代价了,即$\sum_{i=l}^{pos-1}w_i*(a_{pos}-a_i-(pos-i))+\sum_{i=pos+1}^{r}w_i*(a_{i}-a_{pos}-(i-pos))$

考虑左边这一坨(右边同理),化一下式子可得它等于$$\sum_{i=l}^{pos-1}w_i*(a_{pos}-pos-(a_i-i))$$

然后右边也是差不多的形式,于是只要维护$\sum w_i$和$\sum w_i*(a_i-i)$就能快速算出答案了

于是用树状数组维护这两个玩意儿,然后二分找出带权中位数,每一次快速计算答案即可

 //minamoto
#include<iostream>
#include<cstdio>
#include<cmath>
#define ll long long
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=2e5+;const ll P=1e9+;
int n,q;ll a[N],w[N];
namespace SUM{
ll c[N];
inline void add(int x,ll y){
for(;x<=n;x+=x&-x) c[x]+=y;
}
inline ll que(int x){
ll res=;
for(;x;x-=x&-x) res+=c[x];
return res;
}
inline ll query(int l,int r){
if(r<l) return ;
return que(r)-que(l-);
}
}
namespace MUL{
ll c[N];
inline void add(int x,ll y){
y%=P;
for(;x<=n;x+=x&-x)
(c[x]+=y+P)%=P;
}
inline ll que(int x){
ll res=;
for(;x;x-=x&-x) (res+=c[x])%=P;
return res;
}
inline ll query(int l,int r){
if(r<l) return ;
return (que(r)-que(l-)+P)%P;
}
}
inline int getpos(int ql,int qr){
int l=ql,r=qr,mid,res;
while(l<=r){
mid=(l+r)>>;
if(SUM::query(ql,mid)>=SUM::query(mid+,qr)) res=mid,r=mid-;
else l=mid+;
}
return res;
}
void solve(int l,int r){
if(l==r) return (void)(print());
int pos=getpos(l,r);ll res=;
res=(-MUL::query(l,pos)+(SUM::query(l,pos) % P)*(ll)abs(a[pos] - pos)%P+P)%P;
res=(res+MUL::query(pos,r)-SUM::query(pos,r)%P*(a[pos]-pos)%P+P)%P;
print(res);
}
int main(){
// freopen("testdata.in","r",stdin);
n=read(),q=read();
for(int i=;i<=n;++i) a[i]=read();
for(int i=;i<=n;++i){
w[i]=read(),SUM::add(i,w[i]),MUL::add(i,w[i]*(a[i]-i));
}
while(q--){
int x=read(),y=read();
if(x<){
x=-x,SUM::add(x,-w[x]),MUL::add(x,-w[x]*(a[x]-x));
w[x]=y,SUM::add(x,y),MUL::add(x,y*(a[x]-x));
}else solve(x,y);
}
Ot();
return ;
}

洛谷CF1030F Putting Boxes Together(树状数组)的更多相关文章

  1. [洛谷P1198/BZOJ1012][JSOI2008] 最大数 - 树状数组/线段树?

    其实已经学了树状数组和线段树,然而懒得做题,所以至今没写多少博客 Description 现在请求你维护一个数列,要求提供以下两种操作: 1. 查询操作. 语法:Q L 功能:查询当前数列中末尾L个数 ...

  2. 洛谷P3688/uoj#291. [ZJOI2017]树状数组

    传送门(uoj) 传送门(洛谷) 这里是题解以及我的卡常数历程 话说后面那几组数据莫不是lxl出的这么毒 首先不难发现这个东西把查询前缀和变成了查询后缀和,结果就是查了\([l-1,r-1]\)的区间 ...

  3. 洛谷P3368 【模板】树状数组 2

    P3368 [模板]树状数组 2 102通过 206提交 题目提供者HansBug 标签 难度普及/提高- 提交  讨论  题解 最新讨论 暂时没有讨论 题目描述 如题,已知一个数列,你需要进行下面两 ...

  4. 洛谷P3374 【模板】树状数组 1

    P3374 [模板]树状数组 1 140通过 232提交 题目提供者HansBug 标签 难度普及/提高- 提交  讨论  题解 最新讨论 题目描述有误 题目描述 如题,已知一个数列,你需要进行下面两 ...

  5. 洛谷 P3368 【模板】树状数组 2

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  6. 洛谷 P3374 【模板】树状数组 1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

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

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

  8. 树状数组模板(pascal) 洛谷P3374 【模板】树状数组1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

  9. 洛谷 P3368 【模板】树状数组 2(区间修改点查询)

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数数加上x 2.求出某一个数的值 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. ...

随机推荐

  1. spring 事件模式 源代码导读

    一,jdk 事件对象基类 package java.util; import java.io.Serializable; public class EventObject implements Ser ...

  2. 腾讯云图片鉴黄集成到C# SQL Server 怎么在分页获取数据的同时获取到总记录数 sqlserver 操作数据表语句模板 .NET MVC后台发送post请求 百度api查询多个地址的经纬度的问题 try{}里有一个 return 语句,那么紧跟在这个 try 后的 finally {}里的 code 会 不会被执行,什么时候被执行,在 return 前还是后? js获取某个日期

    腾讯云图片鉴黄集成到C#   官方文档:https://cloud.tencent.com/document/product/641/12422 请求官方API及签名的生成代码如下: public c ...

  3. WebService CXF Spring

    web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi=" ...

  4. LeetCode(28)题解:Implement strStr()

    https://leetcode.com/problems/implement-strstr/ 题目: Implement strStr(). Returns the index of the fir ...

  5. luogu2704 炮兵阵地 状态压缩DP

    题目大意:一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),在每一格平原地形上最多可以布置一支炮兵部队,能攻击到的区域:沿横向左右各两格,沿纵向上 ...

  6. Windows ping源码

    需要测试外网的联通性,想到了用ping.网上下载了ping的源代码,调试下整理如下: /******************************************************** ...

  7. html 常用转译空格字符

    本人有时候做表格强迫症,字段有的是3个字有的是4个字,也有两个字的,所有不对齐感觉看着难受, 因此需要用空格来让表头文字对齐,找到了下面几个常用的转译字符. 1.  &160#;不断行的空白( ...

  8. Hihocoder 之 #1097 : 最小生成树一·Prim算法 (用vector二维 模拟邻接表,进行prim()生成树算法, *【模板】)

    #1097 : 最小生成树一·Prim算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 最近,小Hi很喜欢玩的一款游戏模拟城市开放出了新Mod,在这个Mod中,玩家可 ...

  9. 数据结构之 图论---基于邻接矩阵的广度优先搜索遍历(输出bfs遍历序列)

    数据结构实验图论一:基于邻接矩阵的广度优先搜索遍历 Time Limit: 1000MS Memory limit: 65536K 题目描述 给定一个无向连通图,顶点编号从0到n-1,用广度优先搜索( ...

  10. POJ3087 Shuffle'm Up —— 打表找规律 / map判重

    题目链接:http://poj.org/problem?id=3087 Shuffle'm Up Time Limit: 1000MS   Memory Limit: 65536K Total Sub ...