[模板]树状数组
Posted satans
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[模板]树状数组相关的知识,希望对你有一定的参考价值。
题目描述
如题,已知一个数列,你需要进行下面两种操作:
-
将某一个数加上 x
-
求出某区间每一个数的和
输入格式
第一行包含两个正整数 n,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n-1 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 个整数,表示一个操作,具体如下:
-
1 x k
含义:将第 x 个数加上 k -
2 x y
含义:输出区间 [x,y]内每个数的和
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
输入输出样例
5 5 1 5 4 2 3 1 1 3 2 2 5 1 3 -1 1 4 2 2 1 4
14 16
说明/提示
【数据范围】
对于 30% 的数据,1≤n≤81 le n le 81≤n≤8,1≤m≤101le m le 101≤m≤10;
对于 70% 的数据,1≤n,m≤1041le n,m le 10^41≤n,m≤104;
对于 100% 的数据,1≤n,m≤5×1051le n,m le 5 imes 10^51≤n,m≤5×105。
#include<bits/stdc++.h> using namespace std; int m,n,a[510010],x,y,op; inline int lowbit(int pos) { return pos&(-pos); } inline void add(int pos,int x) { while(pos<=n) { a[pos]+=x; pos+=lowbit(pos); } } inline int query(int pos) { int ans=0; while(pos>0) { ans+=a[pos]; pos-=lowbit(pos); } return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&x); add(i,x); } for(int i=1;i<=m;i++) { scanf("%d%d%d",&op,&x,&y); if(op==1) { add(x,y); } else { printf("%d ",query(y)-query(x-1)); } } }
题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数数加上x
2.求出某一个数的值
输入格式
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含2或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x 含义:输出第x个数的值
输出格式
输出包含若干行整数,即为所有操作2的结果。
输入输出样例
5 5 1 5 4 2 3 1 2 4 2 2 3 1 1 5 -1 1 3 5 7 2 4
6 10
说明/提示
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=10000,M<=10000
对于100%的数据:N<=500000,M<=500000
#include<bits/stdc++.h> using namespace std; int m,n,a[510010],x,y,op,b[510010],k; inline int lowbit(int pos) { return pos&(-pos); } inline void add(int pos,int x) { while(pos<=n) { a[pos]+=x; pos+=lowbit(pos); } } inline int query(int pos) { int ans=0; while(pos>0) { ans+=a[pos]; pos-=lowbit(pos); } return ans; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&b[i]); add(i,b[i]-b[i-1]); } for(int i=1;i<=m;i++) { scanf("%d%d",&op,&x); if(op==1) { scanf("%d%d",&y,&k); add(x,k); add(y+1,-k); } else { printf("%d ",query(x)); } } }
题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i<j的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。
Update:数据已加强。
输入格式
第一行,一个数n,表示序列中有n个数。
第二行n个数,表示给定的序列。序列中每个数字不超过10910^9109
输出格式
给定序列中逆序对的数目。
输入输出样例
6 5 4 2 6 3 1
11
说明/提示
对于25%的数据,n≤2500n leq 2500n≤2500
对于50%的数据,n≤4×104n leq 4 imes 10^4n≤4×104。
对于所有数据,n≤5×105n leq 5 imes 10^5n≤5×105
请使用较快的输入输出
(注意离散化要判断是否有相同的数据)
#include<bits/stdc++.h> using namespace std; struct tree { int val; int pos; }b[510010]; int m,n,x,y,op,a[510010],c[510010],cnt; long long int ans; bool compare1(tree a,tree b) { return a.val<b.val; } inline int lowbit(int pos) { return pos&(-pos); } inline void add(int pos,int x) { while(pos<=n) { a[pos]+=x; pos+=lowbit(pos); } } inline long long int query(int pos) { long long int ans=0; while(pos>0) { ans+=a[pos]; pos-=lowbit(pos); } return ans; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&b[i].val); b[i].pos=i; } sort(b+1,b+n+1,compare1); for(int i=1;i<=n;i++) { if(b[i].val!=b[i-1].val) cnt++; c[b[i].pos]=cnt; } for(int i=1;i<=n;i++) { add(c[i],1); ans+=i-query(c[i]); } printf("%lld ",ans); }
以上是关于[模板]树状数组的主要内容,如果未能解决你的问题,请参考以下文章