模板 - 树状数组

整理的算法模板合集: ACM模板


目录

    • 树状数组求逆序对
    • 区间加、求单点值
    • 区间加、区间求和
    • 单点修改、区间求最值
    • 实时求出剩余的数中的第k小的数(树状数组+二分)

树状数组求逆序对

#include 
#include 
#include 
#include 

using namespace std;
typedef long long ll;
const int N = 5000000;

int n,m;
struct node{
    int vis,id;
    bool operator<(const node &t)const{
        return vis < t.vis;
    }
}a[N];
int b[N];
int tree[N];

int lowbit(int x){
    return x & (-x);
}

void update(int x,int k){
    for(;x <= n;x += lowbit(x))
        tree[x] += k;
}

ll ask(int x){
    ll res = 0;
    for(;x;x -= lowbit(x))
        res += tree[x];
    return res;
}

int main(){
    scanf("%d",&n);
    for(int i = 1;i <= n;++i){
        scanf("%d",&a[i].vis);
        a[i].id = i;
    }
    stable_sort(a + 1,a + 1 + n);
    for(int i = 1;i <= n;++i)
        b[a[i].id] = i;
    ll ans = 0;
    for(int i = n;i > 0;i -- ){
        ans += ask(b[i] - 1);
        update(b[i],1);
    }
    printf("%lld\n",ans);
    return 0;
}

区间加、求单点值

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 500007;
typedef long long ll;
int n,m;
int a[N];
ll tree[N];

int lowbit(int x){
    return  x & (-x);
}

void update(int x,int val){
    for(;x <= n;x += lowbit(x))
        tree[x] += val;
}

ll ask(int x){
    ll res = 0;
    for(;x;x -= lowbit(x))
        res += tree[x];
    return res;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i)
        scanf("%d",&a[i]),update(i,a[i] - a[i - 1]);
    for(int i = 1;i <= m;++i){
        char s[2];
        int l,r,d;
        scanf("%s%d",s,&l);
        if(*s == 'C'){
            scanf("%d%d",&r,&d);
            update(l,d),update(r + 1,-d);
        }
        else printf("%lld\n",ask(l));
    }
    return 0;
}

区间加、区间求和

#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 500007;
typedef long long ll;
int n,m;
int a[N];
ll tree[2][N],sum[N];

int lowbit(int x){
    return x & (-x);
}

ll ask(int k,int x){
    ll res = 0;
    for(;x;x -= lowbit(x))
        res += tree[k][x];
    return res;
}

void add(int k,int x,int val){
    for(;x <= n;x += lowbit(x))
        tree[k][x] += val;
}

int main(){
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i){
        scanf("%d",&a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    while(m--){
        char op[2];
        int l,r,d;
        scanf("%s%d%d",op,&l,&r);
        if(op[0] == 'C'){
            scanf("%d",&d);
            add(0,l,d);
            add(0,r + 1,-d);

            add(1,l,l * d);
            add(1,r + 1,-(r + 1) * d);
        }
        else {
            ll ans = sum[r] + (r + 1) * ask(0,r) - ask(1,r);
            ans -= sum[l - 1] + l * ask(0,l - 1) - ask(1,l - 1);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

单点修改、区间求最值

#include
#include

using namespace std;

const int N =1000007, INF = 0x3f3f3f3f;

int n, m;
int tr[N];
int a[N];

int lowbit(int x){
    return x & -x;
}

void modify(int x, int v){
    for(;x <= N;x += lowbit(x)){
        tr[x] = max(tr[x], v);
    }
}

int query(int l, int r){
    int res = -INF;
    for(;r >= l && r - l + 1 >= lowbit(r); r -= lowbit(r)){
        res = max(res, tr[r]);
    }
    while(r >= l){
        res = max(res, a[r]);
        if(r - l + 1 < lowbit(r))r -- ;
        else {
            res = max(res, tr[r]);
            r -= lowbit(r);
        }
    }
    return res;
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1;i <= n;++ i)
        scanf("%d", &a[i]), modify(i, a[i]);
    while(m --){
        int l ,r;
        scanf("%d%d",&l, &r);
        printf("%d\n", query(l, r));
    }
    return 0;
}

实时求出剩余的数中的第k小的数(树状数组+二分)

/*AcWing 244. 谜一样的牛 《算进》P209*/
#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 500007;
typedef long long ll;
int n,m;
int a[N];
int ans[N];
int tree[N];

int lowbit(int x){
    return x & -x;
}

void update(int x,int val){
    for(;x <= n;x += lowbit(x))
        tree[x] += val;
}

int ask(int x){
    int res = 0;
    for(;x;x -= lowbit(x))
        res += tree[x];
    return res;
}

int main(){
    scanf("%d",&n);

    for(int i = 2;i <= n;++i)
        scanf("%d",&a[i]);
    for(int i = 1;i <= n;++i)
        tree[i] = lowbit(i);
        //update(i,1);
    for(int i = n;i;i -- ){
        int k = a[i] + 1;//前面有k个,自己的答案就是k+1
        int l = 1,r = n;
        while(l < r){
                int mid = (l + r) >> 1;
            if(ask(mid) >= k)r = mid;
            else l = mid + 1;
        }
        ans[i] = r;
        update(r,-1);
    }
    for(int i = 1;i <= n;++i)
        printf("%d\n",ans[i]);
    return 0;
}

你可能感兴趣的:(【ACM模板】,#,树状数组)