【前言】

作为一个什么数据结构都不会只会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. hdu_2670Girl Love Value(dp)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2670 Girl Love Value Time Limit: 2000/1000 MS (Java/O ...

  2. 如何给虚拟主机安装phpMyAdmin

    很多虚拟主机没有phpMyAdmin,例如阿里云的云虚拟主机默认的数据库管理工具是DMS,这样好多朋友管理数据库时会觉得不方便.phpMyAdmin是比较大众和常用的Mysql数据库管理软件,我们可以 ...

  3. 【Java提高】---枚举的应用

    枚举 一.枚举和静态常量区别                 讲到枚举我们首先思考,它和public static final String 修饰的常量有什么不同. 我举枚举的两个优点: 1. 保证了 ...

  4. 如何动态修改网页的标题(title)?

    有时候我们需要复用一个页面,但是又希望他们拥有各自的标题,这时候就需要动态的去更改页面的title了,不然所有页面都是一个标题. 这时候就会想到使用js或jQuery去实现了. 1.js方式. 首先, ...

  5. 使用django建博客时遇到的URLcon相关错误以及解决方法。错误提示:类型错误:include0获得一个意外的关键参数app_name

    root@nanlyvm:/home/mydj/mysite# python manage.py runserver Performing system checks... Unhandled exc ...

  6. java常量池詳解

    一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法改变!final修饰的变量有三种:静态变量.实例变量和局部变量,分别表示三种类型的常量. Class文件中的常量池在Clas ...

  7. 《You dont know JS》值相关总结

    值 一:和数组相关的几个需要关注的点 数组可以容纳任何类型的值. 数组声明时不需要预先设置大小.可以动态改变. 使用delete运算符可以将数组中的某个元素删除,但是这个操作不会改变数组的length ...

  8. python通过scapy模块进行arp断网攻击

    前言: 想实现像arpsoof一样的工具 arp断网攻击原理: 通过伪造IP地址与MAC地址实现ARP欺骗,在网络发送大量ARP通信量.攻击者 只要持续不断发送arp包就能造成中间人攻击或者断网攻击. ...

  9. pthread_cond_wait的spurious wakeup问题

    最近在温习pthread的时候,忽然发现以前对pthread_cond_wait的了解太肤浅了.昨晚在看<Programming With POSIX Threads>的时候,看到了pth ...

  10. arcgis地图服务之 identify 服务

    arcgis地图服务之 identify 服务 在近期的一次开发过程中,利用IdentityTask工具查询图层的时候,请求的参数中ImageDisplay的参数出现了错误,导致查询直接不能执行,百度 ...