树状数组仅仅能实现线段树区间改动和区间查询的功能,能够取代不须要lazy tag的线段树。且代码量和常数较小

首先定义一个数组 int c[N]; 并清空 memset(c, 0, sizeof c);

1、单点改动 : c[x] += y; 相应的函数是 change(x, y);

2、求前缀和 :  相应的函数是 int sum(x)

两种操作的复杂度都是O(logn)

模板例如以下:

int c[N], maxn;
inline int Lowbit(int x){return x&(-x);}
void change(int i, int x)//i点增量为x
{
while(i <= maxn)
{
c[i] += x;
i += Lowbit(i);
}
}
int sum(int x){//区间求和 [1,x]
int ans = 0;
for(int i = x; i >= 1; i -= Lowbit(i))
ans += c[i];
return ans;
}

怎样运用树状数组进行区间操作

先定义两个树状数组 X, Y

如今我们须要对一个数组 int a[N]; 进行区间操作:[L, R] += val 即 for i:L to R a[i] += val;

再定义一个 int size = R-L+1 , 即区间长度

相应的改动是

1、X[L] += val;   X[R+1] -= val;

2、Y[L] += -1 * val * (L-1);   Y[R+1] += val * R;

相应的查询是

当我们求和  时在树状数组中操作是 ans = X.sum(k) * k + Y.sum(k)

分类讨论一下k分别在 [1,L-1] , [L, R] , [R+1, +]

1、k[1,L-1]

显然 X.sum(k) == 0 且 Y.sum(k) == 0 -> ans = X.sum(k)*k + Y.sum(k) = 0*i+0 = 0 结果与实际相符。

2、k[L, R]

X.sum(k) * k = X[L] * k = val * k,   Y.sum(k) = Y[L] =  -1 * val * (L-1)

ans = val * k - val * (L-1) = val * ( k - (L-1) );

3、k[R+1, ]

X.sum(k) * k = ( x[L] + x[R] ) * k = 0 * k = 0;

Y.sum(k) = Y[L] + Y[R] = -val * (L-1) + val * R = val * (R-L+1) = val * size

X.sum(k) * k + Y.sum(k) = val * size

证明完成。

下面模版中两个树状数组c[0], c[1] 相应上述的X, Y

区间改动:add(L, R, val)

求 int a[N]的前缀和 get_pre(R)

区间查询:get(L,R)

const int N = 4e5 + 100;
template<class T>
struct Tree{
T c[2][N];
int maxn;
void init(int x){
maxn = x+10; memset(c, 0, sizeof c);
}
inline int lowbit(int x){ return x&-x; }
T sum(T *b, int x){
T ans = 0;
if (x == 0)ans = b[0];
while (x)ans += b[x], x -= lowbit(x);
return ans;
}
void change(T *b, int x, T value){
if (x == 0)b[x] += value, x++;
while (x <= maxn)b[x] += value, x += lowbit(x);
}
T get_pre(int r){
return sum(c[0], r) * r + sum(c[1], r);
}
void add(int l, int r, T value){//区间加权
change(c[0], l, value);
change(c[0], r + 1, -value);
change(c[1], l, value * (-l + 1));
change(c[1], r + 1, value * r);
}
T get(int l, int r){//区间求和
return get_pre(r) - get_pre(l - 1);
}
};
Tree<ll> tree;

好了,回归正题,我们来讲一下这道题的题意:

题意:给定n*m的二维平面 w个操作

int mp[n][m] = { 0 };

1、0 (x1,y1) (x2,y2) value

for i : x1 to x2

for j : y1 to y2

mp[i][j] += value;

2、1 (x1, y1) (x2 y2)

ans1 = 纵坐标在 y1,y2间的总数

ans2 = 横坐标不在x1,x2间的总数

puts(ans1-ans2);

代码例如以下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; typedef long long ll;
const int N = 4e6+10;
int n, m, w;
template<class T>
struct Tree
{
ll c[2][N];
int maxn;
void init(int x)
{
maxn = x+10; memset(c, 0, sizeof c);
}
inline int lowbit(int x)
{
return x&-x;
}
ll sum(ll *b, int x)
{
ll ans = 0;
if (x == 0)ans = b[0];
while (x)ans += b[x], x -= lowbit(x);
return ans;
}
void change(ll *b, int x, ll value)
{
if (x == 0)b[x] += value, x++;
while (x <= maxn)b[x] += value, x += lowbit(x);
}
ll get_pre(int r)
{
return sum(c[0], r) * r + sum(c[1], r);
}
void add(int l, int r, ll value)
{
change(c[0], l, value);
change(c[0], r + 1, -value);
change(c[1], l, value * (-l + 1));
change(c[1], r + 1, value * r);
}
ll get(int l, int r)
{
return get_pre(r) - get_pre(l - 1);
}
}; Tree<ll> x, y; int main()
{
scanf("%d%d%d", &n, &m, &w);
x.init(n); y.init(m);
int tmp;
ll all = 0;
while(w--)
{
scanf("%d", &tmp);
int x1, x2, y1, y2, v;
if(tmp == 0)
{
scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &v);
all += v * (x2-x1+1) * (y2-y1+1);
x.add(x1, x2, v * (y2 - y1 + 1));
y.add(y1, y2, v * (x2 - x1 + 1));
}
if(tmp == 1)
{
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
printf("%I64d\n", y.get(1, y2) - y.get(1, y1-1) - (all - x.get(1, x2) + x.get(1, x1 - 1)));
}
}
return 0;
}



CodeForces 390E Inna and Large Sweet Matrix(树状数组改段求段)的更多相关文章

  1. Codeforces 390E Inna and Large Sweet Matrix 树状数组改段求段

    题目链接:点击打开链接 题意:给定n*m的二维平面 w个操作 int mp[n][m] = { 0 }; 1.0 (x1,y1) (x2,y2) value for i : x1 to x2 for ...

  2. codeforces 390E Inna and Large Sweet Matrix

    本题的主要算法就是区间更新和区间求和: 可以用线段树和树状数组来做: 感觉线段树写的太麻烦了,看到官方题解上说可以用树状数组做,觉得很神奇,以前用过的树状数组都是单点维护,区间求和的: 其实树状数组还 ...

  3. CF390-E. Inna and Large Sweet Matrix(区间更新+区间查询)

    题意很好理解,不说了 题解就是每次把值压缩成一维,比如x上,这样就可以求出任意宽度的整个竖条的和. 如这张图,求的是s5-(s1+s3+s7+s9) 因为可以求出一整竖条和一整横条,我们可以求出是s2 ...

  4. Codeforces 703D Mishka and Interesting sum(树状数组+扫描线)

    [题目链接] http://codeforces.com/contest/703/problem/D [题目大意] 给出一个数列以及m个询问,每个询问要求求出[L,R]区间内出现次数为偶数的数的异或和 ...

  5. CF Educational Codeforces Round 10 D. Nested Segments 离散化+树状数组

    题目链接:http://codeforces.com/problemset/problem/652/D 大意:给若干个线段,保证线段端点不重合,问每个线段内部包含了多少个线段. 方法是对所有线段的端点 ...

  6. Educational Codeforces Round 10 D. Nested Segments 离线树状数组 离散化

    D. Nested Segments 题目连接: http://www.codeforces.com/contest/652/problem/D Description You are given n ...

  7. CodeForces 380C Sereja and Brackets(扫描线+树状数组)

    [题目链接] http://codeforces.com/problemset/problem/380/C [题目大意] 给出一个括号序列,求区间内左右括号匹配的个数. [题解] 我们发现对于每个右括 ...

  8. Educational Codeforces Round 10 D. Nested Segments 【树状数组区间更新 + 离散化 + stl】

    任意门:http://codeforces.com/contest/652/problem/D D. Nested Segments time limit per test 2 seconds mem ...

  9. poj 2155 Matrix (树状数组)

    Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 16797   Accepted: 6312 Descripti ...

随机推荐

  1. Sqli-labs less 11

    Less-11 从这一关开始我们开始进入到post注入的世界了,什么是post呢?就是数据从客户端提交到服务器端,例如我们在登录过程中,输入用户名和密码,用户名和密码以表单的形式提交,提交到服务器后服 ...

  2. angularjs学习笔记3-directive中scope的绑定修饰符

    在angularjs中,一个directive返回一个对象,对象存在很多属性,并且可以在directive中自定义自己的scope,而使用自己的scope是为了防止一个directive被使用在多个地 ...

  3. 初见Python<4>:字典

    序列是python中的一种数据结构,映射是另一种.映射(mapping)通过名字来引用值.python内建的唯一一种映射结构是字典.字典中的值没有特殊的顺序,但都存储在一个特定的键中.键可以是数字.字 ...

  4. [BZOJ4832]抵制克苏恩(概率期望DP)

    方法一:倒推,最常规的期望DP.f[i][a][b][c]表示还要再攻击k次,目前三种随从个数分别为a,b,c的期望攻击英雄次数,直接转移即可. #include<cstdio> #inc ...

  5. [Codeforces #174] Tutorial

    Link: Codeforces #174 传送门 A: 求原根的个数,有一条性质是原根个数为$\phi(\phi(n))$,多了一个不会证的性质 如果要确定哪些是原根的话还是要枚举,不过对于每个数不 ...

  6. [UOJ181]密码锁

    这个完全图随机定向后是一个竞赛图,将它的强连通分量缩点后我们得到的东西类似一条链,每个点往它后面的所有点连边 在这条链上,我们可以把点划分为两个点集$S,T$使得没有从$T$中点到$S$中点的边($S ...

  7. 【贪心】POJ1328-Radar Installation

    [思路] 以每一座岛屿为圆心,雷达范围为半径作圆,记录下与x轴的左右交点.如果与x轴没交点,则直接退出输出“-1”.以左交点为关键字进行排序,从左到右进行贪心.容易知道,离每一个雷达最远的那一座岛与雷 ...

  8. 【MySQL笔记】数据库的查询

    数据库的查询 注:文中 [ ...] 代表该部分可以去掉. 理论基础:对表对象的一组关系运算,即选择(selection).投影(projection)和连接(join) 1.select语句 子语句 ...

  9. 使用织梦开源的分词算法库编写的YII获取分词扩展

    在编辑文章中,很多时候都需要自动根据文章内容获取关键字的功能,因此,本文主要是说明如何在yii中使用织梦开源的分词算法编写一个独立的扩展,可以在不同的模块中使用,步骤如下: 1 到这里下载其他朋友整理 ...

  10. ORACLE启动 切换实例命令

    启动服务器的其他实例 export ORACLE_SID=数据库实例名 sqlplus /nolog conn /as sysdba select name from v$database; !lsn ...