LINK


题目大意

给你n个物品,每一个物品有一个位置p和一个权值w,移动一个物品的代价是移动距离*物品权值

有q个询问:

  1. 把第i个物品的权值变成j
  2. 问把第l到第r个物品移动到一个相邻的区间中\([x,x+r-l]\),问你最小的代价

思路

首先我们很显然地发现一定是可以固定一个位置不动的,然后把剩下的移动到这个位置附近

接下来我们考虑怎么找到这个位置

我们设\(S_{(l,r)}=\sum_{i=l}^r w_i\)

假设我们现在要固定移动\([l,r]\)这个区间,且区间中的第k个位置不变,现在考虑这个状态移动第k+1个位置不变的差量

是:\(S_{(l,k)}*(p_{k+1}-p_{k})-S_{(k+1,r)}*(p_{k+1}-p_{k})\)

当且仅当\(S_{(l,k)}\le S_{(k+1,r)}\)时会使答案更优

所以就可以找到一个最大的位置k满足上述条件

接下来考虑怎么计算固定k的代价

对于\(i\in (l,k)\)代价是\(\sum_{i=l}^k(p_k-p_i-(k-i))*w_i\)

对于\(i\in (k,r)\)代价是\(\sum_{i=k}^r(p_i-p_l-(i-k))*w_i\)

我们令\(a_i=p_i-i\)

有:\(ans=\sum_{i=l}^k(p_k-p_i)*w_i+\sum_{i=k}^r(p_i-p_l)*w_i\)

整理一下变成

\(ans=p_k*(S_{l,k}-S_{k,r})-(\sum_{i=l}^kw_ip_i-\sum_{i=k}^rw_ip_i)\)

于是直接开两个线段树分别维护就可以了


#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define IL inline
#define fu(a,b,c) for(int a=b;a<=c;++a)
#define fd(a,b,c) for(int a=b;a>=c;--a)
#define FLIE ""
IL LL read(){
LL ans=0,w=1;char c=getchar();
while(!isdigit(c)&&c!='-')c=getchar();
if(c=='-')w=-1,c=getchar();
while(isdigit(c))ans=(ans<<1)+(ans<<3)+c-'0',c=getchar();
return ans*w;
}
#define N 300010
#define LD (t<<1)
#define RD (t<<1|1)
#define Mod 1000000007
LL sum1[N<<2],sum2[N<<2];
int a[N],w[N];
int n,q;
LL mod(LL a){a%=Mod;if(a<0)a+=Mod;return a;}
LL add(LL a,LL b){return mod(a+b);}
LL mul(LL a,LL b){return mod(a*b);}
void pushup1(int t){sum1[t]=sum1[LD]+sum1[RD];}
void pushup2(int t){sum2[t]=add(sum2[LD],sum2[RD]);}
void modify1(int t,int l,int r,int pos,LL vl){
if(l==r){sum1[t]=vl;return;}
int mid=(l+r)>>1;
if(pos<=mid)modify1(LD,l,mid,pos,vl);
else modify1(RD,mid+1,r,pos,vl);
pushup1(t);
}
void modify2(int t,int l,int r,int pos,LL vl){
if(l==r){sum2[t]=vl;return;}
int mid=(l+r)>>1;
if(pos<=mid)modify2(LD,l,mid,pos,vl);
else modify2(RD,mid+1,r,pos,vl);
pushup2(t);
}
LL query1_sum(int t,int l,int r,int L,int R){
if(L<=l&&r<=R)return sum1[t];
int mid=(l+r)>>1;
if(R<=mid)return query1_sum(LD,l,mid,L,R);
if(L>mid)return query1_sum(RD,mid+1,r,L,R);
return query1_sum(LD,l,mid,L,mid)+query1_sum(RD,mid+1,r,mid+1,R);
}
int query1_pos(int t,int l,int r,int L,int R,LL vl){
if(l==r)return l;
int mid=(l+r)>>1;
if(R<=mid)return query1_pos(LD,l,mid,L,R,vl);
if(L>mid)return query1_pos(RD,mid+1,r,L,R,vl);
LL suml=query1_sum(LD,l,mid,L,mid);
if(suml>=vl)return query1_pos(LD,l,mid,L,mid,vl);
else return query1_pos(RD,mid+1,r,mid+1,R,vl-suml);
}
LL query2_sum(int t,int l,int r,int L,int R){
if(L<=l&&r<=R)return sum2[t];
int mid=(l+r)>>1;
if(R<=mid)return query2_sum(LD,l,mid,L,R);
if(L>mid)return query2_sum(RD,mid+1,r,L,R);
return add(query2_sum(LD,l,mid,L,mid),query2_sum(RD,mid+1,r,mid+1,R));
}
int main(){
freopen("input.txt","r",stdin);
n=read();q=read();
fu(i,1,n)a[i]=read(),a[i]-=i;;
fu(i,1,n)w[i]=read();
fu(i,1,n){
modify1(1,1,n,i,w[i]);
modify2(1,1,n,i,mul(a[i],w[i]));
}
while(q--){
int x=read(),y=read();
if(x<0){
x=-x;
w[x]=y;
modify1(1,1,n,x,w[x]);
modify2(1,1,n,x,mul(a[x],w[x]));
}else{
LL sum=query1_sum(1,1,n,x,y);
int pos=query1_pos(1,1,n,x,y,(sum+1)>>1);
LL ans=0;
ans=add(ans,mul(a[pos],add(query1_sum(1,1,n,x,pos),-query1_sum(1,1,n,pos,y))));
ans=add(ans,add(-query2_sum(1,1,n,x,pos),query2_sum(1,1,n,pos,y)));
printf("%lld\n",ans);
}
}
return 0;
}

Codeforces 1030F 【线段树】【好题】的更多相关文章

  1. Lucky Array CodeForces - 121E (线段树,好题)

    题目链接 题目大意: 定义只含数字$4,7$的数字为幸运数, 给定序列, 区间加正数, 区间询问多少个幸运数 题解: 对于每一个数, 求出它和第一个比它大的幸运数之差, 则问题转化为区间加,查询$0$ ...

  2. Codeforces Round #393 (Div. 2) (8VC Venture Cup 2017 - Final Round Div. 2 Edition) E - Nikita and stack 线段树好题

    http://codeforces.com/contest/760/problem/E 题目大意:现在对栈有m个操作,但是顺序是乱的,现在每输入一个操作要求你输出当前的栈顶, 注意,已有操作要按它们的 ...

  3. [AHOI 2009] 维护序列(线段树模板题)

    1798: [Ahoi2009]Seq 维护序列seq Time Limit: 30 Sec  Memory Limit: 64 MB Description 老师交给小可可一个维护数列的任务,现在小 ...

  4. POJ 3468 线段树裸题

    这些天一直在看线段树,因为临近期末,所以看得断断续续,弄得有些知识点没能理解得很透切,但我也知道不能钻牛角尖,所以配合着刷题来加深理解. 然后,这是线段树裸题,而且是最简单的区间增加与查询,我参考了A ...

  5. hdu-1540线段树刷题

    title: hdu-1540线段树刷题 date: 2018-10-18 19:55:21 tags: acm 刷题 categories: ACM-线段树 概述 哇,,,这道线段树的题可以说是到目 ...

  6. hdu-5023线段树刷题

    title: hdu-5023线段树刷题 date: 2018-10-18 13:32:13 tags: acm 刷题 categories: ACM-线段树 概述 这道题和上次做的那道染色问题一样, ...

  7. poj-2777线段树刷题

    title: poj-2777线段树刷题 date: 2018-10-16 20:01:07 tags: acm 刷题 categories: ACM-线段树 概述 这道题是一道线段树的染色问题,,, ...

  8. zoj-1610线段树刷题

    title: zoj-1610线段树刷题 date: 2018-10-16 16:49:47 tags: acm 刷题 categories: ACM-线段树 概述 这道题是一道简单的线段树区间染色问 ...

  9. hdu 1754 I Hate It 线段树基础题

    Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老师的要求, ...

  10. 【LOJ6062】「2017 山东一轮集训 Day2」Pair(线段树套路题)

    点此看题面 大致题意: 给出一个长度为\(n\)的数列\(a\)和一个长度为\(m\)的数列\(b\),求\(a\)有多少个长度为\(m\)的子串与\(b\)匹配.数列匹配指存在一种方案使两个数列中的 ...

随机推荐

  1. python学习笔记glob模块

    python有许多的类库,现将学习记录下来,以供以后回顾复习: 1.glob模块 用于文件名操作,匹配指定目录下的文件,返回的是目录加文件名,常用的有两个函数: glob(pattern),返回匹配的 ...

  2. 生产消费模式:多线程读写队列ConcurrentQueue

    需求:现需要将多个数据源的数据导入到目标数据库,这是一个经典的生产消费应用的例子. 直接上代码,看下实现: // 初始化列队缓冲区 队列大小为100 IDataCollection<List&l ...

  3. RabbitMQ 之消息确认机制(事务+Confirm)

    概述 在 Rabbitmq 中我们可以通过持久化来解决因为服务器异常而导致丢失的问题,除此之外我们还会遇到一个问题:生产者将消息发送出去之后,消息到底有没有正确到达 Rabbit 服务器呢?如果不错得 ...

  4. play的过滤类怎么实现继承问题

    原文: Example: public class Secure extends Controller {          @Before     static void checkAuthenti ...

  5. 解决:make:cc 命令未找到的解决方法

    安装Redis的时候报这个错误 原因:未安装gcc 解决方法:安装gcc 自动安装,包括依赖库[root@VM_220_111_centos redis-3.2.9]# yum -y install ...

  6. 设计模式--命令模式C++实现

    命令模式C++实现 1定义 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求队列或者记录请求日志,可以提供命令的撤销和恢复功能 2类图 角色描述: Receiver接受者角色,就 ...

  7. 【Demo】CSS3 动画

    CSS3 动画(@keyframes,animation) CSS3 @keyframes 规则 要创建CSS3动画,你将不得不了解@keyframes规则. @keyframes规则是创建动画. @ ...

  8. 三十 Python分布式爬虫打造搜索引擎Scrapy精讲—将selenium操作谷歌浏览器集成到scrapy中

    1.爬虫文件 dispatcher.connect()信号分发器,第一个参数信号触发函数,第二个参数是触发信号,signals.spider_closed是爬虫结束信号 # -*- coding: u ...

  9. C++调用Python脚本中的函数

    1.环境配置 安装完python后,把python的include和lib拷贝到自己的工程目录下 然后在工程中包括进去 2.例子 先写一个python的测试脚本,如下 这个脚本里面定义了两个函数Hel ...

  10. HDU 4828 逆元+catalan数

    Grids Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Subm ...