系列索引:

分块

阅:《「分块」数列分块入门 1-9 by hzwer》

树状数组 Binary Indexed Tree

时间复杂度 每次操作 \(O(\log n)\),空间复杂度 \(O(n)\)。

Pure

下标从 1 开始。

ll t[N];

inline int lowbit(int x) {return x&-x; }

inline void update(int x, ll val) {
for (; x<=n; x+=lowbit(x)) t[x]+=val;
}
inline ll sum(int x) {
ll res=0;
for (; x; x-=lowbit(x)) res+=t[x];
return res;
}

2 Dimensions

void update(int x, int y, int z) {
int i = x;
while (i <= n) {
int j = y;
while (j <= m) {
t[i][j] += z;
j += lowbit(j);
}
i += lowbit(i);
}
} int sum(int x, int y) { // prefix
int res = 0, i = x;
while (i > 0) {
int j = y;
while (j > 0) {
res += t[i][j];
j -= lowbit(j);
}
i -= lowbit(i);
}
return res;
}

线段树 Segment Tree

时间复杂度 每次操作 \(O(\log n)\),空间复杂度 \(O(4n)\)。

Standard

单点修改,区间求和:

#define lson k<<1, l, mid
#define rson k<<1|1, mid+1, r int t[N<<2]; void modify(int k, int l, int r, int x) {
if (l==r&&l==x) {++t[k]; return; }
register int mid=l+r>>1;
if (x<=mid) modify(lson, x);
if (mid<x) modify(rson, x);
++t[k];
}
int query(int k, int l, int r, int x, int y) {
if (x<=l&&r<=y) return t[k];
register int mid=l+r>>1, res=0;
if (x<=mid) res+=query(lson, x, y);
if (mid<y) res+=query(rson, x, y);
return res;
}

区间修改,区间求和:

ll t[N<<2], laz[N<<2];

inline void add(int k, int l, int r, ll val) {
laz[k]+=val;
t[k]+=(r-l+1)*val;
}
inline void pd(int k, int l, int r, int mid) {
if (!laz[k]) return;
add(lson, laz[k]), add(rson, laz[k]);
laz[k]=0;
}
void modify(int k, int l, int r, int x, int y, ll val) {
if (x<=l&&r<=y) {add(k, l, r, val); return; }
int mid=l+r>>1;
pd(k, l, r, mid);
if (x<=mid) modify(lson, x, y, val);
if (mid<y) modify(rson, x, y, val);
t[k]=t[k<<1]+t[k<<1|1];
}
ll query(int k, int l, int r, int x, int y) {
if (x<=l&&r<=y) return t[k];
int mid=l+r>>1; ll res=0;
pd(k, l, r, mid);
if (x<=mid) res+=query(lson, x, y);
if (mid<y) res+=query(rson, x, y);
return res;
}

有运算优先级:如同时支持区间乘和区间加,将标记设计为先乘 a 再加 b,那么区间加时直接加 b 即可,而区间乘时需要将 a 和 b 都乘上一个数。

int lazy[N<<2], sum[N<<2], lazy2[N<<2];

void build(int k, int l, int r) {
lazy2[k] = 1;
if (l==r) { sum[k] = data[l]; return; }
int mid = l+r >> 1;
build(k<<1, l, mid);
build((k<<1)+1, mid+1, r);
sum[k] = ((ll)sum[k<<1] + sum[(k<<1)+1]) % MOD;
}
void add(int k, int l, int r, int v) {
lazy[k] = ((ll)lazy[k] + v) % MOD;
sum[k] = (sum[k] + (ll)(r-l+1) * v) % MOD;
}
void mul(int k, int l, int r, int v) {
lazy[k] = ((ll)lazy[k] * v) % MOD;
lazy2[k] = ((ll)lazy2[k] * v) % MOD;
sum[k] = ((ll)sum[k] * v) % MOD;
}
void pushdown(int k, int l, int r, int mid) {
if (lazy2[k]!=1) {
mul(k<<1, l, mid, lazy2[k]);
mul((k<<1)+1, mid+1, r, lazy2[k]);
lazy2[k] = 1;
}
if (lazy[k]) {
add(k<<1, l, mid, lazy[k]);
add((k<<1)+1, mid+1, r, lazy[k]);
lazy[k] = 0;
}
}
void modify(int k, int l, int r, int x, int y, int v) {
if (l>=x && r<=y) {add(k, l, r, v); return;}
int mid = l+r >> 1;
pushdown(k, l, r, mid);
if (x<=mid) modify(k<<1, l, mid, x, y, v);
if (y>mid) modify((k<<1)+1, mid+1, r, x, y, v);
sum[k] = ((ll)sum[k<<1] + sum[(k<<1)+1]) % MOD;
}
void modify2(int k, int l, int r, int x, int y, int v) {
if (l>=x && r<=y) {mul(k, l, r, v); return;}
int mid = l+r >> 1;
pushdown(k, l, r, mid);
if (x<=mid) modify2(k<<1, l, mid, x, y, v);
if (y>mid) modify2((k<<1)+1, mid+1, r, x, y, v);
sum[k] = ((ll)sum[k<<1] + sum[(k<<1)+1]) % MOD;
}
int query(int k, int l, int r, int x, int y) {
if (l>=x && r<=y) return sum[k];
int mid = l+r >> 1, res = 0;
pushdown(k, l, r, mid);
if (x<=mid) res = ((ll)res + query(k<<1, l, mid, x, y)) % MOD;
if (y>mid) res = ((ll)res + query((k<<1)+1, mid+1, r, x, y)) % MOD;
return res;
}

标记永久化

对于树套树,主席树等使用到线段树的比较复杂的数据结构,打标记后 pushdown、pushup 是很费劲的。

思路:不下传标记;在路过该节点的时候把修改对答案的影响加上,来省去标记下放的过程。

zkw Segment Tree

int zkw; ll t[N<<2], laz[N<<2];

inline void update(int x, int y, ll val) {
ll l=0, r=0, f=1;
for (x+=zkw-1, y+=zkw+1; x^y^1; x>>=1, y>>=1, f<<=1) {
t[x]+=val*l, t[y]+=val*r;
if (~x&1) laz[x^1]+=val, t[x^1]+=val*f, l+=f;
if (y&1) laz[y^1]+=val, t[y^1]+=val*f, r+=f;
}
for (; x; x>>=1, y>>=1) t[x]+=val*l, t[y]+=val*r;
} inline ll query(int x, int y) {
ll res=0, l=0, r=0, f=1;
for (x+=zkw-1, y+=zkw+1; x^y^1; x>>=1, y>>=1, f<<=1) {
if (laz[x]) res+=laz[x]*l;
if (laz[y]) res+=laz[y]*r;
if (~x&1) res+=t[x^1], l+=f;
if (y&1) res+=t[y^1], r+=f;
}
for (; x; x>>=1, y>>=1) res+=laz[x]*l, res+=laz[y]*r;
return res;
} for (zkw=1; zkw<=n+1; zkw<<=1);
for (int i=zkw+1; i<=zkw+n; i++) scanf("%lld", t+i);
for (int i=zkw-1; i>0; --i) t[i]=t[i<<1]+t[i<<1|1];

NOIp 数据结构专题总结 (2):分块、树状数组、线段树的更多相关文章

  1. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

  2. 树状数组 && 线段树应用 -- 求逆序数

    参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...

  3. hdu1394(枚举/树状数组/线段树单点更新&区间求和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 ...

  4. hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. hdu 5147 Sequence II【树状数组/线段树】

    Sequence IITime Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...

  6. 【洛谷4396/BZOJ3236】[AHOI2013]作业(莫队+分块/树状数组/线段树)

    题目: 洛谷4396 BZOJ3236(权限) 这题似乎BZOJ上数据强一些? 分析: 这题真的是--一言难尽 发现题面里没说权值的范围,怕出锅就写了离散化.后来经过面向数据编程(以及膜神犇代码)知道 ...

  7. 数据结构--树状数组&&线段树--基本操作

    随笔目的:方便以后对树状数组(BIT)以及基本线段树的回顾 例题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 例题:hdu 1166 敌兵布阵 T ...

  8. [SDOI2009]HH的项链-树状数组/线段树

    树状数组: #include<bits/stdc++.h> using namespace std; ; int id[maxn],tree[maxn],vis[maxn],num[max ...

  9. 「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)

    学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...

  10. 【bzoj2819】Nim(dfs序+树状数组/线段树)

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2819 首先根据SG定理,可得若每堆石子数量的异或值为0,则后手必胜,反之先手必胜.于是 ...

随机推荐

  1. Jmeter 循环控制器 遍历结果

    1.测试计划,添加Mysql jar包 2.线程组 3.JDBC Connection Configuration,配置Mysql 4.添加JDBC Request,将查询出的数据对应的存入usern ...

  2. Card Collector AtCoder - 5168(二分图匹配的HALL定理)

    题意: 给定一个H行W列的矩阵,在矩阵的格点上放带权值的卡片(一个点上能放多张). 现在从每行每列各拿走一张卡片(没有可以不拿),求可以拿到的最大权值. 卡片数N<=1e5,H,W<=1e ...

  3. workflow-core 简介

    最近想做一个OA相关的网站开发,一直都听说有workflow的东西,之前也断断续续学习过 Workflow Foundation 4.0,还是没有搞明白到底能够用它做什么 但还是觉得workflow在 ...

  4. Codeforces 1114B (贪心)

    题面 传送门 分析 答案很好看出,显然是选最大的m*k个数 那么如何构造方案呢 我们把最大的m*k个数的位置标记为1,其他标记为0 从左到右维护一个ptr,记录有标记的数的个数,如果当前有m个有标记的 ...

  5. CodeForces 295B Greg and Graph (floyd+离线)

    <题目链接> 题目大意:给定$n$个点的有向完全带权图$(n\leq500)$,现在进行$n$次操作,每次操作从图中删除一个点(每删除一个点,都会将与它相关联的边都删除),问你每次删点之前 ...

  6. 20180223-logging模块

    Python的logging模块提供了标准的日志接口,可以通过它存储各种格式的日志,logging的日志可以依次分为debug().info().warning().error().cirtical( ...

  7. Backend事后诸葛亮

    事后诸葛亮 设想和目标 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件想解决初学编程语言的入门困难.定义的不算太清楚,没有仔细地调查用户入门的困难之处. ...

  8. windows10安装docker[含百度网盘docker安装包]

    在win10上安装 docker(比较简单) 安装步骤: 现在 Docker 有专门的 Win10 专业版系统的安装包,需要开启Hyper-V. 1.开启 Hyper-V 程序和功能 启用或关闭Win ...

  9. vue,一路走来(4)--vuex

    补充 调用外部js,详细介绍如何调用函数. 1.首先在main.js里引用文件 2.然后算是和jquery框架一样需要所谓的入口函数吧 不过令我烦恼的是,在应用的文件中需要把他包含在另一个函数里,才可 ...

  10. 毕设问题(2) fastjson 的过滤器使用(SSH hibernate)以及转换对象出现 $ref

    毕业设计,用SSH框架,但是想要做出异步请求数据的效果,使用了ajax方式,其中数据传递的类型为json.ajax使用用的jQuery的ajax.其实struts里也支持ajax功能,但是我觉得用太多 ...