树状数组和线段树

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在这里插入图片描述在这里插入图片描述

树状数组的离散化

在这里插入图片描述

题目模板

例题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]);
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值