|算法讨论|树状数组 学习笔记

题目
[树状数组]BZOJ 1452:开多个树状数组解决问题
[树状数组, 并查集]BZOJ 3211:并查集辅助树状数组求值


模板及讲解

知识点:
1. 点修改,求x~y区间值
2. 区间修改,求某一点值
3. 二维树状数组
4. 离散化求逆序对

1 点修改,求x~y区间值

#include<cstdio>      
#include<algorithm>      
#include<cstring>      
#include<queue>      
#define ms(i,j) memset(i,j, sizeof i);      
using namespace std;    
int a[500005];   
int n,m;  
int abss(int x){return x>=0 ? x : -x;}  
int lowbit(int x)  
{  
    return x&(-x);  
}  
int getsum(int x)//求1~x的和   
{  
    int ret = 0;  
    for (int i=x;i>0;i-=lowbit(i))  
    {  
        ret += a[i];  
    }  
    return ret;  
}  
void addsum(int x, int y)//1~x加y   
{  
    for (int i=x;i<=n;i+=lowbit(i))  
    {  
        a[i] += y;  
    }  
}  
int main()      
{      
    a[0] = 0;  
    scanf("%d%d", &n, &m);  
    for (int i=1;i<=n;i++)  
    {  
        int x;  
        scanf("%d", &x);  
        addsum(i,x);  
    }  
    for (int i=1;i<=m;i++)  
    {  
        int ty;  
        scanf("%d", &ty);  
        if (ty==1)  
        {  
            int x,k;  
            scanf("%d%d", &x, &k);  
            addsum(x,k);  
        } else  
        {  
            int x,y;  
            scanf("%d%d", &x, &y);  
            printf("%d\n", abss(getsum(y)-getsum(x-1)));  
        }  
    }  
    return 0;      
}      

2 区间修改,求某一点值

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#include<vector>  
using namespace std;  
#define ms(i,j) memset(i,j,sizeof i);  
int n,m;  
const int maxn = 500005;  
int a[maxn];//a记录的是比i-lowbit(i)多的值  
int lowbit(int x)  
{  
    return x&(-x);  
}  
int add(int x, int v)  
{  
    for (int i=x;i<=n;i+=lowbit(i))  
    {  
        a[i] += v;  
    }  
}  
int sub(int x)  
{  
    int ret = 0;  
    for (int i=x;i>0;i-=lowbit(i))  
    {  
        ret += a[i];  
    }  
    return ret;  
}  
int main()  
{  
    scanf("%d%d", &n ,&m);  
    ms(a,0);  
    for (int i=1;i<=n;i++)  
    {  
        int x;  
        scanf("%d", &x);  
        add(i,x);  
        add(i+1,-x);  
    }  
    for (int i=1;i<=m;i++)  
    {  
        int ty;  
        scanf("%d", &ty);  
        if(ty==1)  
        {  
            int x,y,k;  
            scanf("%d%d%d", &x,&y,&k);  
            add(x,k); add(y+1,-k);  
        } else   
        {  
            int x;  
            scanf("%d", &x);  
            printf("%d\n", sub(x));  
        }  
    }  
    system("pause");  
    return 0;  
}  

3 二维树状数组
二维树状数组

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
using namespace std;  
#define ms(i,j) memset(i, j, sizeof i);  
int a[1050][1050];  
int n;  
int lowbit(int x)  
{  
    return x&(-x);  
}  
void addsum(int x, int y, int v)//得到和   
{  
    for (int i=x;i<=n;i+=lowbit(i))  
    {  
        for (int j=y;j<=n;j+=lowbit(j))  
        {  
            a[i][j] += v;  
        }  
    }  
}  
int getsum(int x, int y)//加   
{  
    int ret = 0;  
    for (int i=x;i>0;i-=lowbit(i))  
    {  
        for (int j=y;j>0;j-=lowbit(j))  
        {  
            ret += a[i][j];  
        }  
    }  
    return ret;  
}  
int main()  
{  
    scanf("%d", &n);  
    int m;  
    while(scanf("%d", &m)==1&&m!=3)  
    {  
       if (m==1)  
       {  
          int x,y,k;  
          scanf("%d%d%d", &x, &y, &k);  
          addsum(x+1,y+1,k);   
       } else  
       {  
           int x1,y1,x2,y2;  
           scanf("%d%d%d%d", &x1, &y1, &x2, &y2);  
           printf("%d\n", getsum(x2+1,y2+1)-getsum(x1,y2+1)-getsum(x2+1,y1)+getsum(x1,y1));  
           //公式,因为防止0所以都+1   
       }  
    }  
    system("pause");  
    return 0;  
}  

4 离散化求逆序对

#include<cstdio>    
#include<cstring>    
#include<algorithm>    
using namespace std;    
#define ms(i,j) memset(i, j, sizeof i);    
struct node  
{  
       int v;  
       int num;  
       bool operator<(const node &a) const  
       {  
            return v<a.v;  
        }  
}t[40005];//输入数   
int hash[40005];//映射表   
int a[40005];//树状数组   
int n;  
int ans = 0;  
int lowbit(int x)  
{  
    return x&(-x);  
}  
int getsum(int x)//取值   
{  
    int ret = 0;  
    for (int i=x;i>0;i-=lowbit(i))  
    {  
        ret += a[i];  
    }  
    return ret;  
}  
int addsum(int x, int v)//加值   
{  
    for (int i=x;i<=n;i+=lowbit(i))  
    {  
        a[i] += v;  
    }   
}  
int main()    
{    
    scanf("%d", &n);  
    for (int i=1;i<=n;i++)  
    {  
        scanf("%d", &t[i].v);  
        t[i].num = i;  
    }  
    sort(t+1,t+1+n);//排序   
    for (int i=1;i<=n;i++)  
    {  
        hash[t[i].num] = i;//离散化   
    }  
    for (int i=1;i<=n;i++)  
    {  
        addsum(hash[i], 1);  
        ans += i-getsum(hash[i]);  
        //getsum(hash[i]): 有多少个数在hash[i]右边   
        //i 已经插了几个数   
    }   
    printf("%d\n",ans);  
    system("pause");    
    return 0;    
}    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值