算法笔记--树状数组

区间和模板:

const int N=1e5+5;
int c[N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}

1.单点更新,区间求和

HDU - 1166

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+5;
int c[N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T,a,l,r;
    int cnt=0;
    string s;
    cin>>T;
    while(T--)
    {
        cin>>n;
        mem(c,0); 
        for(int i=1;i<=n;i++)cin>>a,update(i,a);
        cout<<"Case "<<++cnt<<":"<<endl;
        while(cin>>s)
        {
            if(s=="End")break;
            if(s=="Query")
            {
                cin>>l>>r;
                cout<<sum(r)-sum(l-1)<<endl;
            }
            else if(s=="Add")
            {
                cin>>l>>r;
                update(l,r);
            }
            else if(s=="Sub")
            {
                cin>>l>>r;
                update(l,-r);
            }
        } 
    }
    return 0;
}
View Code

2.区间更新,单点求值

有点像差分标记

HDU - 1556

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+5;
int c[N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int l,r;
    while(cin>>n)
    {
        mem(c,0);
        for(int i=1;i<=n;i++)
        {
            cin>>l>>r;
            update(l,1);
            update(r+1,-1);
        } 
        for(int i=1;i<=n;i++)
        {
            cout<<sum(i);
            if(i!=n)cout<<' ';
            else cout<<endl;
        } 
    }
    return 0;
}
View Code

3.逆序数问题

HDU - 2689

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+5;
int c[N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
int sum(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int d)
{
    while(x<=n)
    {
        c[x]+=d;
        x+=lowbit(x);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    while(cin>>n)
    {
        mem(c,0);
        int tot=0;
        for(int i=1;i<=n;i++)
        {
            cin>>t;
            update(t,1);
            tot+=i-sum(t);//sum(t)是小于等于t的个数 
        }
        cout<<tot<<endl;
    }
    return 0;
}
View Code

HDU - 2838

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+5;
int n;
struct 
{
    int cnt;
    ll sum;
}c[N];
int lowbit(int x)
{
    return x&(-x);
}
ll _sum(int x)
{
    ll ret=0;
    while(x)
    {
        ret+=c[x].sum;
        x-=lowbit(x);
    }
    return ret;
}
int cnt(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x].cnt;
        x-=lowbit(x);
    }
    return ret;
}
void update(int x,int d,int _d)
{
    while(x<=n)
    {
        c[x].sum+=d;
        c[x].cnt+=_d;
        x+=lowbit(x);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    while(cin>>n)
    {
        for(int i=1;i<=n;i++)c[i].sum=c[i].cnt=0;
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            cin>>t;
            update(t,t,1);
            sum+=((ll)t*(i-cnt(t))+_sum(n)-_sum(t));
        }
        cout<<sum<<endl;
    }
    return 0;
}
View Code

4.多维树状数组

二维:

HDU - 2642

树状数组+容斥

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e3+5;
int n;
bool vis[N][N]={false};
int c[N][N];
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int y,int d)
{
    for(int i=x;i<N;i+=lowbit(i))
    {
        for(int j=y;j<N;j+=lowbit(j))
        {
            c[i][j]+=d;
        }
    }
}
int sum(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+=c[i][j];
        }
    }
    return ret;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int x,y,_x,_y;
    string s;
    while(cin>>n)
    {
        mem(c,0);
        mem(vis,false);
        for(int i=1;i<=n;i++)
        {
            cin>>s;
            if(s=="B")
            {
                cin>>x>>y;
                x++;
                y++;
                if(!vis[x][y])update(x,y,1),vis[x][y]=true;
            } 
            else if(s=="D")
            {
                cin>>x>>y;
                x++;
                y++;
                if(vis[x][y])update(x,y,-1),vis[x][y]=false;
            }
            else if(s=="Q")
            {
                cin>>x>>_x>>y>>_y;
                x++,y++,_x++,_y++;
                if(x>_x)swap(x,_x);
                if(y>_y)swap(y,_y);
                cout<<sum(_x,_y)+sum(x-1,y-1)-sum(x-1,_y)-sum(_x,y-1)<<endl; 
            }
        }
    }
    return 0;
}
View Code

三维:

HDU - 3584

区间更新,单点求值

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=105;
int a[N][N][N];
int n;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int y,int z)
{
    for(int i=x;i<=n;i+=lowbit(i))
    {
        for(int j=y;j<=n;j+=lowbit(j))
        {
            for(int k=z;k<=n;k+=lowbit(k))
            {
                a[i][j][k]++;
            }
        }
    }
}
ll sum(int x,int y,int z)
{
    ll res=0;
    for(int i=x;i>0;i-=lowbit(i))
    {
        for(int j=y;j>0;j-=lowbit(j))
        {
            for(int k=z;k>0;k-=lowbit(k))
            {
                res+=a[i][j][k];
            }
        }
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int x,y,z,_x,_y,_z;
    int t,m;
    while(cin>>n>>m)
    {
        mem(a,0);
        while(m--)
        {
            cin>>t;
            if(t)
            {
                cin>>x>>y>>z>>_x>>_y>>_z;
                update(x,y,z);
                update(_x+1,y,z);
                update(x,_y+1,z);
                update(x,y,_z+1);
                update(x,_y+1,_z+1);
                update(_x+1,y,_z+1);
                update(_x+1,_y+1,z);
                update(_x+1,_y+1,_z+1); 
            }
            else
            {
                cin>>x>>y>>z;
                cout<<sum(x,y,z)%2<<endl;
            }
        }
    }
    return 0;
} 
View Code

5.离散化树状数组

POJ - 2299

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long 
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=5e5+10;
struct node
{
    int v;
    int id;
    bool operator < (const node t) const
    {
        return v<t.v;
    }
}a[N];
int mp[N];
int c[N]; 
int n;
int lowbit(int x)
{
    return x&(-x);
}
void update(int x,int d)
{
    while(x<=n)c[x]+=d,x+=lowbit(x);
}
int sum(int x)
{
    int res=0;
    while(x)res+=c[x],x-=lowbit(x);
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n&&n)
    {
        mem(c,0);
        for(int i=1;i<=n;i++)
        {
            cin>>a[i].v;
            a[i].id=i;
        }
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++)mp[a[i].id]=i;
        ll ans=0;
        for(int i=1;i<=n;i++)
        {
            update(mp[i],1);
            ans+=i-sum(mp[i]);
        }
        cout<<ans<<endl;
    }
    return 0;
} 
View Code

6.区间更新,区间查询

不错的博客:https://www.cnblogs.com/lcf-2000/p/5866170.html

模板:

const int N=1e6+5;
ll c1[N],c2[N];
int n;
void add(int x,int y)
{
    for(int i=x;i<=n;i+=i&(-i))c1[i]+=y,c2[i]+=(ll)x*y;
}
ll sum(int x)
{
    ll ans=0;
    for(int i=x;i>0;i-=i&(-i))ans+=c1[i]*(x+1)-c2[i];
    return ans;
}

http://codevs.cn/problem/1082/

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e6+5;
ll c1[N],c2[N];
int n;
void add(int x,int y)
{
    for(int i=x;i<=n;i+=i&(-i))c1[i]+=y,c2[i]+=(ll)x*y;
}
ll sum(int x)
{
    ll ans=0;
    for(int i=x;i>0;i-=i&(-i))ans+=c1[i]*(x+1)-c2[i];
    return ans;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t,q,a,b,x;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>t;
        add(i,t);
        add(i+1,-t);
    }
    cin>>q;
    while(q--)
    {
        cin>>t;
        if(t==1)
        {
            cin>>a>>b>>x;
            add(a,x);
            add(b+1,-x);
        }
        else if(t==2)
        {
            cin>>a>>b;
            cout<<sum(b)-sum(a-1)<<endl;
        }
    }
    //for(int i=1;i<=n;i++)cout<<c1[i]<<' '<<c2[i]<<endl;
    return 0;
}
View Code

参考博客:http://blog.csdn.net/yexiaohhjk/article/details/51077545

原文地址:https://www.cnblogs.com/widsom/p/7749930.html