博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于树状数组
阅读量:7052 次
发布时间:2019-06-28

本文共 6495 字,大约阅读时间需要 21 分钟。

树状数组是一种十分优秀的数据结构,拥有常数非常小的特点,好写好调,在一些应用上比线段树要优秀许多。下面我来介绍下树状数组(基础知识请看蓝书或其他神犇的blog,蒟蒻在这里就不多提了)。

区间修改&&区间查询

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数数加上x
2.求出某一个数的和

这里要引入差分数组这种东西,我们记d[i] = a[i] - a[i-1](a为原数组),这样我们记sigma(d[i]) = a[i] ,为什么呢,观察式子sigma(d[i]) = a[1] + a[2] - a[1] +a[3]...这样一直下去就得到了我们的原数组。

有什么用呢?如果我们往一段区间上加k,在差分数组上如何体现呢?我们举个栗子:
a:1,2,3,4,5
d:1,1,1,1,1
2~4加1
如果我们盲目的在2到4上加1,就会发现会影响后面的数(因为是前缀和),所以我们在2这个位置加一,用树状数组更新,在5的位置减一用树状数组更新就ok了
a:1,3,4,5,5
d:1,2,1,1,0
这样就没问题了吧?总的时间是操作数×log(n)。

/*************************************************************************    > Author: Drinkwater-cnyali    > Created Time: 2017/6/13 10:22:21 ************************************************************************/#include
#include
#include
#include
#include
#include
using namespace std;typedef long long LL;#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)char buff[1<<25], *buf = buff;#define mem(a, b) memset((a), b, sizeof(a))template
inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }template
inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }int Fread(){ int sum = 0, fg = 1; for(; !isdigit(*buf) ; ++buf)if(*buf == '-')fg = -1; for(; isdigit(*buf); ++buf)sum = sum * 10 + *buf - '0'; return sum * fg;}int read(){ int sum = 0,fg = 1;char c = getchar(); while(c < '0' || c > '9') { if (c == '-') fg = -1; c = getchar(); } while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); } return sum * fg;}const int maxn = 1000000;const int inf = 0x3f3f3f3f;int n,m;int c[maxn],a[maxn];inline int lowbit(int x) { return (x & (-x));}inline void updata(int x,int num){ for(; x <= n; x += lowbit(x)) c[x] += num;}inline int query(int x){ int ans = 0; for( ; x > 0; x -= lowbit(x)) ans += c[x]; return ans;} int main(){ fread(buff,1,1<<25,stdin); n = Fread(), m = Fread(); REP(i,1,n)a[i] = Fread(), updata(i,a[i] - a[i-1]); REP(i,1,m) { int t = Fread(); if(t == 1) { int x = Fread(), y = Fread(),k = Fread(); updata(x,k),updata(y+1,-k); } if(t == 2) { int x = Fread(); printf("%d\n",query(x)); } } return 0;}

如题,已知一个数列,你需要进行下面两种操作:

1.将某区间每一个数加上x
2.求出某区间每一个数的和

这道题显然是线段树区间更新的裸题,这里我们要对式子进行变形

一个区间和我们记为sigma(a[i]) = d[1] + (d[1] + d[2]) + (d[1] + d[2]+ d[3]) + ..+(…d[n])
= nd[1] - (n-1)d[2] + ..+d[n]
= n * (d[1] + ..+d[n]) - (0d[1] + 1d[2] + ..+(n-1)d[n])
这样我们就只需要维护一个d的前缀和和(i-1)*d[i]的前缀和就好了。

/*************************************************************************    > Author: Drinkwater-cnyali    > Created Time: 2017/6/13 15:36:58 ************************************************************************/#prag\ma GCC optimize("O4")#include
#include
#include
#include
#include
#include
using namespace std;typedef long long LL;#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)char buff[1<<25], *buf = buff;#define mem(a, b) memset((a), b, sizeof(a))template
inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }template
inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }LL Fread(){ LL sum = 0, fg = 1; for(; !isdigit(*buf) ; ++buf)if(*buf == '-')fg = -1; for(; isdigit(*buf); ++buf)sum = sum * 10 + *buf - '0'; return sum * fg;}int read(){ int sum = 0,fg = 1;char c = getchar(); while(c < '0' || c > '9') { if (c == '-') fg = -1; c = getchar(); } while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); } return sum * fg;}const int maxn = 100000+10;const int inf = 0x3f3f3f3f;LL n,m;LL a[maxn],c1[maxn],c2[maxn];int lowbit(int x) { return (x & (-x));}void updata(int x,int num,int t){ if(t == 1) for( ; x <= n; x += lowbit(x)) c1[x] += num; else for(; x <= n; x += lowbit(x)) c2[x] += num;} LL query(int x,int t){ LL ans = 0; if(t == 1) for(; x > 0; x -= lowbit(x)) ans += c1[x]; else for(; x > 0; x -= lowbit(x)) ans += c2[x]; return ans;}int main(){ fread(buff,1,1<<25,stdin); n = Fread(), m = Fread(); REP(i,1,n) a[i] = Fread(), updata(i,a[i]-a[i-1],1),updata(i,(a[i]-a[i-1])*(i-1),2); REP(i,1,m) { LL t = Fread(); if(t == 1) { LL x = Fread(), y = Fread(), k = Fread(); updata(x,k,1),updata(y + 1, -k, 1); updata(x, (x-1) * k, 2), updata(y+1, -y * k, 2); } if(t == 2) { LL x = Fread(), y = Fread(); LL sum1 = query(x-1,1) * (x-1) - query(x-1,2); LL sum2 = query(y,1) * y - query(y,2); printf("%lld\n",sum2 - sum1); } } return 0;}

逆序对

这里我们以权值为下标构建树状数组统计比当前点大的数的个数,边读边更新。

/*************************************************************************    > Author: Drinkwater-cnyali    > Created Time: 2017/5/25 10:51:38 ************************************************************************/#include
#include
#include
#include
#include
#include
using namespace std;typedef long long LL;#define REP(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)#define DREP(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)#define debug(...) fprintf(stderr, __VA_ARGS__)#define mem(a, b) memset((a), b, sizeof(a))template
inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }template
inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }int read(){ int sum = 0, fg = 1; char c = getchar(); while(c < '0' || c > '9') { if (c == '-') fg = -1; c = getchar(); } while(c >= '0' && c <= '9') { sum = sum * 10 + c - '0'; c = getchar(); } return sum * fg;}const int maxn = 100000;const int mod = 99999997;typedef pair
P;P a[maxn],b[maxn];int n;int c[maxn],t[maxn];bool cmp(P u,P v){ return u.first < v.first;}int lowbit(int x){ return (x & (-x));}void updata(int x){ while(x <= n) t[x]++,x += lowbit(x);}int get_sum(int x){ int ans = 0; while(x > 0) { ans += t[x]; x -= lowbit(x); } return ans;}int main(){ n = read(); REP(i,1,n)a[i].first = read(),a[i].second = i; REP(i,1,n)b[i].first = read(),b[i].second = i; sort(a+1,a+1+n,cmp);sort(b+1,b+1+n,cmp); REP(i,1,n)c[a[i].second] = b[i].second; int ans = 0; for(int i = n; i >= 1; --i) { ans = (ans%mod + get_sum(c[i])%mod)%mod; updata(c[i]); } cout<
<

转载于:https://www.cnblogs.com/brodrinkwater/p/7527984.html

你可能感兴趣的文章
list详解
查看>>
oracle学习篇六:子查询
查看>>
北风网VIP6级学习视频地址
查看>>
团队小组开发nabc分析
查看>>
jQuery mobile
查看>>
CF893F:Subtree Minimum Query(线段树合并)
查看>>
1305. [CQOI2009]跳舞【最大流+二分】
查看>>
Windows Phone(二) WP7数据库连接(SQLite数据库)
查看>>
浮动与清除问题
查看>>
97. Interleaving String
查看>>
node.js 使用ejs模板引擎时后缀换成.html
查看>>
JAVA使用urlrewrite实现伪静态化
查看>>
python with ···as··· 用法
查看>>
C#.NET里面抽象类和接口有什么区别
查看>>
xampp下Apache服务的启动
查看>>
恐惧的缘由
查看>>
【转载】什么是堆和栈,它们在哪儿?
查看>>
$(document).ready(function(){}),$().ready(function(){})和$(function(){}) 三者区别
查看>>
学号 2017-2018-20172309 《程序设计与数据结构》第9周学习总结
查看>>
HTML标签自定义属性
查看>>