树状数组的离散化
题目模板
例题1.
题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某一个数加上 xx
求出某区间每一个数的和
输入格式
第一行包含两个正整数 n,mn,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 nn 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 mm 行每行包含 33 个整数,表示一个操作,具体如下:
1 x k 含义:将第 xx 个数加上 kk
2 x y 含义:输出区间 [x,y][x,y] 内每个数的和
输出格式
输出包含若干行整数,即为所有操作 22 的结果。
输入输出
5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4
输出
14
16
【数据范围】
----------------------------------树状数组代码------------------------------------------
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
const int inf = 0x3f3f3f3f;//1061109567
typedef long long ll;
using namespace std;
const int N = 5000005;
int lowbit(int x) { return x & (-x); }
int c[N], a; int n;
void add(int i, int x)
{
while (i <=n)
{
c[i] += x;
i += lowbit(i);
}
}
int getsum(int i)
{
int ans = 0;
while (i > 0)
{
ans += c[i];
i -= lowbit(i);
}
return ans;
}
int main()
{
int m; cin >> n >> m;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a); add(i, a);
}
while (m--)
{
int ch; scanf("%d", &ch);
if (ch == 1)//修改
{
int x, k; scanf("%d%d", &x, &k);
add(x, k);
}
if (ch == 2)//输出
{
int x, y; scanf("%d%d", &x, &y);
cout << getsum(y) - getsum(x - 1) << endl;
}
}
}
----------------------------------线段树代码------------------------------------------
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
int n,m;
int ans;
int he=0;
int input[500010];
struct node
{
int left,right;
int num;
}tree[2000010];
void build(int left,int right,int index)
{
he++;
tree[index].left=left;
tree[index].right=right;
if(left==right)
return ;
int mid=(right+left)/2;
build(left,mid,index*2);
build(mid+1,right,index*2+1);
}
int add(int index)
{
if(tree[index].left==tree[index].right)
{
//cout<<index<<" "<<input[tree[index].right]<<endl;
tree[index].num=input[tree[index].right];
return tree[index].num;
}
tree[index].num=add(index*2)+add(index*2+1);
return tree[index].num;
}
void my_plus(int index,int dis,int k)
{
tree[index].num+=k;
if(tree[index].left==tree[index].right)
return ;
if(dis<=tree[index*2].right)
my_plus(index*2,dis,k);
if(dis>=tree[index*2+1].left)
my_plus(index*2+1,dis,k);
}
void search(int index,int l,int r)
{
//cout<<index<<" ";
if(tree[index].left>=l && tree[index].right<=r)
{
ans+=tree[index].num;
return ;
}
if(tree[index*2].right>=l)
search(index*2,l,r);
if(tree[index*2+1].left<=r)
search(index*2+1,l,r);
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
scanf("%d",&input[i]);
build(1,n,1);
add(1);
for(int i=1;i<=m;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
if(a==1)
{
my_plus(1,b,c);
}
if(a==2)
{
ans=0;
search(1,b,c);
printf("%d\n",ans);
}
}
}
例题2
题目描述
如题,已知一个数列,你需要进行下面两种操作:
将某区间每一个数数加上 xx;
求出某一个数的值。
输入格式
第一行包含两个整数 NN、MM,分别表示该数列数字的个数和操作的总个数。
第二行包含 NN 个用空格分隔的整数,其中第 ii 个数字表示数列第 ii 项的初始值。
接下来 MM 行每行包含 22 或 44个整数,表示一个操作,具体如下:
操作 11: 格式:1 x y k 含义:将区间 [x,y][x,y] 内每个数加上 kk;
操作 22: 格式:2 x 含义:输出第 xx 个数的值。
输出格式
输出包含若干行整数,即为所有操作 22 的结果。
输入
5 5
1 5 4 2 3
1 2 4 2
2 3
1 1 5 -1
1 3 5 7
2 4
输出
2
10
----------------------------------------树状数组------------------------------
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <algorithm>
#include <iomanip>
#include <map>
#include <queue>
#include <vector>
#include <set>
const int inf = 0x3f3f3f3f;//1061109567
typedef long long ll;
using namespace std;
const int N = 5000005;
int lowbit(int x) { return x & (-x); }
int c[N], a[N]; int n;
void add(int i, int x)
{
while (i <=n)
{
c[i] += x;
i += lowbit(i);
}
}
int getsum(int i)
{
int ans = 0;
while (i > 0)
{
ans += c[i];
i -= lowbit(i);
}
return ans;
}
int main()
{
int m; cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
while (m--)
{
int ch;
scanf("%d", &ch);
if (ch == 1)//修改
{
int x, y, k;
scanf("%d%d%d", &x,&y,&k);
add(x, k); add(y + 1, -k);
}
if (ch == 2)//输出
{
int x; scanf("%d", &x);
cout << a[x] + getsum(x) << endl;
}
}
}
----------------------------------------线段树-----------------------------
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
using namespace std;
int n,m;
int ans;
int input[500010];
struct node
{
int left,right;
int num;
}tree[2000010];
void build(int left,int right,int index)
{
tree[index].num=0;
tree[index].left=left;
tree[index].right=right;
if(left==right)
return ;
int mid=(right+left)/2;
build(left,mid,index*2);
build(mid+1,right,index*2+1);
}
/*int add(int index)
{
if(tree[index].left==tree[index].right)
{
tree[index].num=input[tree[index].right];
return tree[index].num;
}
tree[index].num=add(index*2)+add(index*2+1);
return tree[index].num;
}
*/
void pls(int index,int l,int r,int k)
{
if(tree[index].left>=l && tree[index].right<=r)
{
tree[index].num+=k;
return ;
}
if(tree[index*2].right>=l)
pls(index*2,l,r,k);
if(tree[index*2+1].left<=r)
pls(index*2+1,l,r,k);
}
void search(int index,int dis)
{
ans+=tree[index].num;
if(tree[index].left==tree[index].right)
return ;
if(dis<=tree[index*2].right)
search(index*2,dis);
if(dis>=tree[index*2+1].left)
search(index*2+1,dis);
}
int main()
{
int n,m;
cin>>n>>m;
build(1,n,1);
for(int i=1;i<=n;i++)
scanf("%d",&input[i]);
for(int i=1;i<=m;i++)
{
int a;
scanf("%d",&a);
if(a==1)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
pls(1,x,y,z);
}
if(a==2)
{
ans=0;
int x;
scanf("%d",&x);
search(1,x);
printf("%d\n",ans+input[x]);
}
}
}