题意:

现在有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. Handlebars的基本用法 Handlebars.js使用介绍 http://handlebarsjs.com/ Handlebars.js 模板引擎 javascript/jquery模板引擎——Handlebars初体验 handlebars.js 入门(1) 作为一名前端的你,必须掌握的模板引擎:Handlebars 前端数据模板handlebars与jquery整

    Handlebars的基本用法 使用Handlebars,你可以轻松创建语义化模板,Mustache模板和Handlebars是兼容的,所以你可以将Mustache导入Handlebars以使用 Ha ...

  2. 不是技术牛人,如何拿到国内IT巨头的Offer--转

    http://blog.csdn.net/lsldd/article/details/13506263 不久前,byvoid面阿里星计划的面试结果截图泄漏,引起无数IT屌丝的羡慕敬仰.看看这些牛人,N ...

  3. 基于bootstrap_网站汇总页面

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. nginx-伤心的事

    今天测试接口,总是出问题,测试了两天,整个流程就卡在最后一步. 每次采用curl,request等请求访问我的服务器都会返回403状态码,网上找了很多资料 有权限的,有静态文件的,然而很多都没有什么卵 ...

  5. PHP琐碎学习

    在子类中如果定义了__construct则不会调用父类的__construct,如果需要同时调用父类的构造函数,需要使用parent::__construct()显式的调用. class Car { ...

  6. android 编程小技巧(持续中)

    first:     Intent跳转一般存用于Activity类,可是若要在非activity类里跳转的话,解决方法是在startActivity(intent)前加mContext即上下文,终于为 ...

  7. VC实现趋势图绘制

    本文参考pudn上一个完整工程,在pudn搜索“50815867CurveDrawing”即可找到源代码.   上图是使用VS2010重写了该软件后的效果图,下面再贴出关键代码: // Plot.cp ...

  8. javascript event事件兼容性处理

    ie 6-8支持event事件,ff浏览器不支持 获取鼠标点击位置的坐标 document.onclick = function(){ alert(event.clientX +"-&quo ...

  9. em和i , b和Strong 的区别

    这两对标签最大区别就是一个给搜索引擎看的,一个是给用户看的. b标签和strong标签给我们的主观感受都是加粗,但对搜索引擎来说b标签和普通的文字并没有什么区别,而strong标签却是起强调作用的. ...

  10. 超全!整理常用的iOS第三方资源(转)

    超全!整理常用的iOS第三方资源 一:第三方插件 1:基于响应式编程思想的oc 地址:https://github.com/ReactiveCocoa/ReactiveCocoa 2:hud提示框 地 ...