zoukankan      html  css  js  c++  java
  • 洛谷CF1030F Putting Boxes Together(树状数组)

    题意:

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

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

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

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

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

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

    带权中位数为满足$sum_{i=1}^x w_igeq 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)$就能快速算出答案了

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

     1 //minamoto
     2 #include<iostream>
     3 #include<cstdio>
     4 #include<cmath>
     5 #define ll long long
     6 using namespace std;
     7 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
     8 char buf[1<<21],*p1=buf,*p2=buf;
     9 inline int read(){
    10     #define num ch-'0'
    11     char ch;bool flag=0;int res;
    12     while(!isdigit(ch=getc()))
    13     (ch=='-')&&(flag=true);
    14     for(res=num;isdigit(ch=getc());res=res*10+num);
    15     (flag)&&(res=-res);
    16     #undef num
    17     return res;
    18 }
    19 char sr[1<<21],z[20];int C=-1,Z;
    20 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    21 inline void print(int x){
    22     if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x;
    23     while(z[++Z]=x%10+48,x/=10);
    24     while(sr[++C]=z[Z],--Z);sr[++C]='
    ';
    25 }
    26 const int N=2e5+5;const ll P=1e9+7;
    27 int n,q;ll a[N],w[N];
    28 namespace SUM{
    29     ll c[N];
    30     inline void add(int x,ll y){
    31         for(;x<=n;x+=x&-x) c[x]+=y;
    32     }
    33     inline ll que(int x){
    34         ll res=0;
    35         for(;x;x-=x&-x) res+=c[x];
    36         return res;
    37     }
    38     inline ll query(int l,int r){
    39         if(r<l) return 0;
    40         return que(r)-que(l-1);
    41     }
    42 }
    43 namespace MUL{
    44     ll c[N];
    45     inline void add(int x,ll y){
    46         y%=P;
    47         for(;x<=n;x+=x&-x)
    48         (c[x]+=y+P)%=P;
    49     }
    50     inline ll que(int x){
    51         ll res=0;
    52         for(;x;x-=x&-x) (res+=c[x])%=P;
    53         return res;
    54     }
    55     inline ll query(int l,int r){
    56         if(r<l) return 0;
    57         return (que(r)-que(l-1)+P)%P;
    58     }
    59 }
    60 inline int getpos(int ql,int qr){
    61     int l=ql,r=qr,mid,res;
    62     while(l<=r){
    63         mid=(l+r)>>1;
    64         if(SUM::query(ql,mid)>=SUM::query(mid+1,qr)) res=mid,r=mid-1;
    65         else l=mid+1;
    66     }
    67     return res;
    68 }
    69 void solve(int l,int r){
    70     if(l==r) return (void)(print(0));
    71     int pos=getpos(l,r);ll res=0;
    72     res=(-MUL::query(l,pos)+(SUM::query(l,pos) % P)*(ll)abs(a[pos] - pos)%P+P)%P;
    73     res=(res+MUL::query(pos,r)-SUM::query(pos,r)%P*(a[pos]-pos)%P+P)%P;
    74     print(res);
    75 }
    76 int main(){
    77 //    freopen("testdata.in","r",stdin);
    78     n=read(),q=read();
    79     for(int i=1;i<=n;++i) a[i]=read();
    80     for(int i=1;i<=n;++i){
    81         w[i]=read(),SUM::add(i,w[i]),MUL::add(i,w[i]*(a[i]-i));
    82     }
    83     while(q--){
    84         int x=read(),y=read();
    85         if(x<0){
    86             x=-x,SUM::add(x,-w[x]),MUL::add(x,-w[x]*(a[x]-x));
    87             w[x]=y,SUM::add(x,y),MUL::add(x,y*(a[x]-x));
    88         }else solve(x,y);
    89     }
    90     Ot();
    91     return 0;
    92 }
  • 相关阅读:
    【摘录】使用实体框架、Dapper和Chain的仓储模式实现策略
    关于微软HttpClient使用,避免踩坑
    在网上摘录一段对于IOC的解析,比较直观,大家观摩观摩
    经历招聘中面试求职的点滴
    在面试中忽然发现DateTime的一些...
    GCC的内存边界对齐
    如何删除Weblogic域
    电蚊拍选购参考
    Localizing WPF with .resx files
    C#操作串口总结
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/9764334.html
Copyright © 2011-2022 走看看