【前言】

作为一个什么数据结构都不会只会CDQ分治和分块的蒟蒻,面对区间加&区间求和这么难的问题,怎么可能会写线段树呢

于是,用CDQ分治解决区间加&区间求和这篇习作应运而生


【Part.I】区间加&区间求和的数据结构做法

【一】线段树

裸题...

1141ms

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
#define lson lc, l, mid
#define rson rc, mid+1, r
typedef long long ll;
const int N=1e5+;
inline ll read(){
char c=getchar();ll x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} int n,Q,op,x,y;
struct SegmentTree{
struct meow{ ll sum, tag; } t[N<<];
inline void paint(int x,int l,int r,ll v){
t[x].tag+= v;
t[x].sum+= (r-l+)*v;
}
inline void pushDown(int x,int l,int r){
if(t[x].tag){
paint(lson, t[x].tag);
paint(rson, t[x].tag);
t[x].tag=;
}
}
void build(int x,int l,int r){
if(l==r) t[x].sum=read();
else{
build(lson);
build(rson);
t[x].sum=t[lc].sum+t[rc].sum;
}
}
void Add(int x,int l,int r,int ql,int qr,ll v){
if(ql<=l && r<=qr) paint(x,l,r,v);
else{
pushDown(x,l,r);
if(ql<=mid) Add(lson, ql, qr, v);
if(mid<qr) Add(rson, ql, qr, v);
t[x].sum=t[lc].sum+t[rc].sum;
}
}
ll Que(int x,int l,int r,int ql,int qr){
if(ql<=l && r<=qr) return t[x].sum;
else{
pushDown(x,l,r);
ll ans=;
if(ql<=mid) ans+=Que(lson, ql, qr);
if(mid<qr) ans+=Que(rson, ql, qr);
return ans;
}
}
}S;
int main(){
//freopen("in","r",stdin);
n=read(); Q=read();
S.build(,,n);
while(Q--){
op=read();x=read();y=read();
if(op==) S.Add(,,n,x,y,read() );
else printf("%lld\n", S.Que(,,n,x,y) );
}
}

SegmentTree

【二】树状数组

考虑每个位置的贡献,维护$a[i]$和$i*a[i]$

477ms

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e5+;
inline ll read(){
char c=getchar();ll x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} int n,Q,op,x,y;
struct meow{
ll c[N];
inline void add(int p,ll v) {for(;p<=n;p+=p&-p) c[p]+=v;}
inline ll sum(int p) {ll re=; for(;p;p-=p&-p) re+=c[p]; return re;}
inline ll sum(int l,int r) {return sum(r)-sum(l-);}
}C1,C2;
struct BinaryIndexTree{
inline void Add(int l,int r,ll v){
C1.add(l,v); C1.add(r+,-v);
C2.add(l,l*v); C2.add(r+,-(r+)*v);
}
inline ll Que(int l,int r){
return (r-l+)*C1.sum(,l) + (r+)*C1.sum(l+,r) - C2.sum(l+,r);
}
}A;
int main(){
// freopen("in","r",stdin);
n=read(); Q=read();
for(int i=;i<=n;i++) A.Add(i,i,read() );
while(Q--){
op=read();x=read();y=read();
if(op==) A.Add(x,y,read() );
else printf("%lld\n", A.Que(x,y) );
}
}

BinaryIndexTree


【Part.II】区间加&区间求和的CDQ分治做法

首先我们明确CDQ分治是什么 参见[偏序关系与CDQ分治]【学习笔记】

用CDQ分治解决单点加&区间求和  区间加&单点求值 是很容易的,但要两个都是区间就不太方便了

但经过两个多小时的研究,终于做出来啦

区间加&区间求和可以算是二维偏序问题,可以只用排序和CDQ分治不借助任何数据结构解决

首先把修改和询问都拆成两个

我们对时间排序,对位置进行CDQ分治

问题在于对于$[l,r]$这样一个加操作,$r<p$的当然很方便了,但对$l \le p \le r$的每个$p$贡献都是不一样的

一开始困扰了我好久

突然想到可以维护一个$val$表示当前每在位置上移动一个距离总体的贡献应该改变多少,再维护一个$last$表示上一个位置

然后更新当前的贡献时用$val$乘移动的距离就可以了

其实本质就是得到了计算$[l,mid]$中修改的贡献后每一个位置的值应该是多少

问题解决!撒花

1251ms 时间垫底了.....

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
typedef long long ll;
const int N=1e5+;
inline ll read(){
char c=getchar();ll x=,f=;
while(c<''||c>''){if(c=='-')f=-;c=getchar();}
while(c>=''&&c<=''){x=x*+c-'';c=getchar();}
return x*f;
} int n,Q,m,op,l,r;
ll a[N],v,ans[N];
struct meow{
int x,type,qid; ll v;
meow(){}
meow(int b,int c,int d,ll e):x(b),type(c),qid(d),v(e){}
bool operator <(const meow &r) const {return x==r.x ? type<r.type : x<r.x;}
}q[N<<],t[N<<]; void CDQ(int l,int r){
if(l==r) return ;
int mid=(l+r)>>;
CDQ(l, mid); CDQ(mid+, r);
int i=l, j=mid+, p=l;
ll now=, val=; int last=;
while(i<=mid || j<=r){
if(j>r || (i<=mid && q[i]<q[j]) ){
now+=(q[i].x-last)*val; last=q[i].x;
if(q[i].type!=) val+=q[i].v;
t[p++]=q[i++];
}else{
now+=(q[j].x-last)*val; last=q[j].x;
if(!q[j].type) ans[ q[j].qid ]+= now*q[j].v ;
t[p++]=q[j++];
}
}
for(int i=l;i<=r;i++) q[i]=t[i];
} int main(){
freopen("in","r",stdin);
n=read(); Q=read(); int p=;
for(int i=;i<=n;i++) v=read(), q[++m]=meow(i-,-,,v), q[++m]=meow(i,,,-v); for(int i=;i<=Q;i++){
op=read(); l=read(); r=read();
if(op==) v=read(), q[++m]=meow(l-,-,,v), q[++m]=meow(r,,,-v);
else p++, q[++m]=meow(l-,,p,-), q[++m]=meow(r,,p,);
}
CDQ(,m);
for(int i=;i<=p;i++) printf("%lld\n",ans[i]);
}

CDQ分治


【Part.III】应用

这玩意常数又大又需要离线有什么用啊

1.我们可以出题坐标特别大强制线段树来离线离散化

2.可以推广到一系列区间修改与查询问题

[用CDQ分治解决区间加&区间求和]【习作】的更多相关文章

  1. 「模板」 线段树——区间乘 && 区间加 && 区间求和

    「模板」 线段树--区间乘 && 区间加 && 区间求和 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long l ...

  2. cdq分治解决三维偏序

    问题背景 在三维坐标系中有n个点,坐标为(xi,yi,zi). 定义一个点A比一个点B小,当且仅当xA<=xB,yA<=yB,zA<=zB.问对于每个点,有多少个点比它小.(n< ...

  3. 【BZOJ】1798: [Ahoi2009]Seq 维护序列seq 线段树多标记(区间加+区间乘)

    [题意]给定序列,支持区间加和区间乘,查询区间和取模.n<=10^5. [算法]线段树 [题解]线段树多重标记要考虑标记与标记之间的相互影响. 对于sum*b+a,+c直接加上即可. *c后就是 ...

  4. cdq分治解决区间问题

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

  5. COGS.1317.数列操作c(分块 区间加 区间求和)

    题目链接 #include<cmath> #include<cstdio> #include<cctype> #include<algorithm> u ...

  6. P4315 月下“毛景树” (树链剖分+边剖分+区间覆盖+区间加+区间最大值)

    题目链接:https://www.luogu.org/problem/P4315 题目大意: 有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的.但是这棵“毛景树”有着神奇的魔力 ...

  7. CDQ 分治解决和点对有关的问题

    具体可以去这篇博客学习: https://oi-wiki.org/misc/cdq-divide/

  8. 陌上花开——CDQ分治

    传送门 “CDQ分治”从来都没有听说过,写了这题才知道还有这么神奇的算法. (被逼无奈).w(゚Д゚)w 于是看了不少dalao的博客,对CDQ算法粗浅地了解了一点.(想要了解CDQ的概念,可以看下这 ...

  9. [学习笔记]CDQ分治和整体二分

    序言 \(CDQ\) 分治和整体二分都是基于分治的思想,把复杂的问题拆分成许多可以简单求的解子问题.但是这两种算法必须离线处理,不能解决一些强制在线的题目.不过如果题目允许离线的话,这两种算法能把在线 ...

随机推荐

  1. ABB安全区域(全局区域)的指令解析

    VAR wztemporary wzone;//VAR:变量 //wztemporary:全局区域数据类型(wztemporary临时全局区域数据.wzstationary固定式全局区域)wzone: ...

  2. POJ 2253 Frogger(Dijkstra变形——最短路径最大权值)

    题目链接: http://poj.org/problem?id=2253 Description Freddy Frog is sitting on a stone in the middle of ...

  3. Redis Cluster集群搭建与应用

    1.redis-cluster设计 Redis集群搭建的方式有多种,例如使用zookeeper,但从redis 3.0之后版本支持redis-cluster集群,redis-cluster采用无中心结 ...

  4. 《并行程序设计导论》——Pthreads

    这部分不需要看了. 因为C++11和BOOST比这个Pthreads要好一点. 如果不考虑移植性,在Windows平台上用核心编程的东西比C++11和BOOST更好控制.

  5. [机器学习]-[数据预处理]-中心化 缩放 KNN(二)

    上次我们使用精度评估得到的成绩是 61%,成绩并不理想,再使 recall 和 f1 看下成绩如何? 首先我们先了解一下 召回率和 f1. 真实结果 预测结果 预测结果   正例 反例 正例 TP 真 ...

  6. 2017-06-19 (cp mkdir rm 运行级别及修改)

    mkdir 用于创建目录 mkdir  -p  递归创建目录 mkdir -p /linux/linux rm 用于删除文件与目录 rm -r  删除目录 -f  强制删除   (一般情况下 rf 组 ...

  7. Velocity动态拼接字符串

    1.在全局定义一个变量: #set($varName = "") 2.拼接字符串病截取字符串: #foreach( $role in $adminUser.roles) #set( ...

  8. CentOs下安装PHP扩展curl

    服务器运行一段时间后,可能突然会需求添加某个扩展,如curl.pdo.xmlrpc等,这就需要在不重新编译Linux PHP的情况下独立添加扩展. 1.安装crul wget http://curl. ...

  9. python_virtualenvwrapper安装与使用

    如何创建当前python版本虚拟环境? 1. 安装virtualenv pip install -i https://pipy.doubanio.com/simple virtualenv 2. 创建 ...

  10. Log4j扩展使用--自定义输出

    写在前面的话 log4j支持自定义的输出.所有的输出都实现了自Appender接口.一般来说,自定义输出值需要继承AppenderSkeleton类,并实现几个方法就可以了. 写这篇博客,我主要也是想 ...