【树状数组】【模板】讲解

【树状数组】【模板】讲解

int getsum(int x)//区间查询
{
    int ans = 0;
    for( ; x; x -= lowbit(x))
        ans += val[x];
    return ans;
}

void add(int x)//单点修改
{
    for( ; x <= mx; x += lowbit(x))
        val[x]++;
}

void discretize()//离散化
{
    for(int i = 1; i <= n; i++)
        b[i] = a[i];
    sort(b + 1, b + 1 + n);
    int cnt = unique(b + 1, b + 1 + n) - (b + 1);
    for(int i = 1; i <= n; i++)
        id[i] = lower_bound(b + 1, b + 1 + cnt, a[i]) - b;
}

 for(int i = 1; i <= n; i++)//求逆序对
 {
     add(id[i]);
     ans += i - getsum(id[i]);
 }

求逆序对的文章
树状数组总结‘’
区间修改 模板
区间修改 原理讲解
树状数组代码(good)

//设c是差分数组的前缀和

//区间修改:将l - r增加x
void add(int x, int v)
{
    for( ; x <= n + 1; x += lowbit(x))
        c[x] += v;
}

//给区间[l, r]加上x
void range_add(int l, int r, int x)
{
    add(l,x);//将l加x
    add(r+1,-x);将r + 1减x
}

//单点查询:查询x处的值
int getsum(int x)
{
    int ans = 0;
    for( ; x; x -= lowbit(x))
        ans += c[x];
    return ans;
}
//假设sum1维护d[i]的前缀和,sum2维护d[i] * i的前缀和

//在数组数组中直接修改某点的值
void add(ll p, ll x){
    for(int i = p; i <= n; i += i & -i)
        sum1[i] += x, sum2[i] += x * p;
}

//给区间(l, r)加上x
void range_add(ll l, ll r, ll x){
    add(l, x), add(r + 1, -x);
}

//位置p的前缀和
ll ask(ll p){
    ll res = 0;
    for(int i = p; i; i -= i & -i)
        res += (p + 1) * sum1[i] - sum2[i];
    return res;
}

//区间[l, r]的和
ll range_ask(ll l, ll r){
    return ask(r) - ask(l - 1);
}

二维树状数组

LL c[mx][mx];

//单点修改,将(x, y)加上v
void add(int x, int y, int v)
{
    for(int i = x; i <= n + 1; i += lowbit(i))
        for(int j = y; j <= n + 1; j += lowbit(j))
        c[i][j] = c[i][j] + v;
}

//区间查询: 求左上角为(1,1)右下角为(x,y) 的矩阵和
LL getsum(int x, int y)
{
    LL ans = 0;
    for(int i = x; i; i -= lowbit(i))
        for(int j = y; j; j -= lowbit(j))
        ans = ans + c[i][j];
    return ans;
}

//区间查询:求(x1, y1) (x2, y2)构成的矩形的和

ans = getsum(x2, y2) - getsum(x2, y1 - 1) - getsum(x1 - 1, y2) + getsum(x1 - 1, y1 - 1)
区间修改 单点查询

//二维前缀和:
sum[i][j]=sum[i−1][j]+sum[i][j−1]−sum[i−1][j−1]+a[i][j]

//差分数组d[i][j] 表示 a[i][j] 与 a[i−1][j]+a[i][j−1]−a[i−1][j−1] 的差。

//单点修改,将(x, y)加上v
void add(int x, int y, int v)
{
    for(int i = x; i <= n + 1; i += lowbit(i))
        for(int j = y; j <= n + 1; j += lowbit(j))
        c[i][j] = c[i][j] + v;
}

void range_add(int xa, int ya, int xb, int yb, int z){
    add(xa, ya, z);
    add(xa, yb + 1, -z);
    add(xb + 1, ya, -z);
    add(xb + 1, yb + 1, z);
}

//区间查询: 求左上角为(1,1)右下角为(x,y) 的矩阵和
LL getsum(int x, int y)
{
    LL ans = 0;
    for(int i = x; i; i -= lowbit(i))
        for(int j = y; j; j -= lowbit(j))
        ans = ans + c[i][j];
    return ans;
}
//区间修改 + 区间查询

void add(ll x, ll y, ll z){
    for(int X = x; X <= n; X += X & -X)
        for(int Y = y; Y <= m; Y += Y & -Y){
            t1[X][Y] += z;
            t2[X][Y] += z * x;
            t3[X][Y] += z * y;
            t4[X][Y] += z * x * y;
        }
}

void range_add(ll xa, ll ya, ll xb, ll yb, ll z){ //(xa, ya) 到 (xb, yb) 的矩形
    add(xa, ya, z);
    add(xa, yb + 1, -z);
    add(xb + 1, ya, -z);
    add(xb + 1, yb + 1, z);
}

ll ask(ll x, ll y){
    ll res = 0;
    for(int i = x; i; i -= i & -i)
        for(int j = y; j; j -= j & -j)
            res += (x + 1) * (y + 1) * t1[i][j]
                - (y + 1) * t2[i][j]
                - (x + 1) * t3[i][j]
                + t4[i][j];
    return res;
}

ll range_ask(ll xa, ll ya, ll xb, ll yb){
    return ask(xb, yb) - ask(xb, ya - 1) - ask(xa - 1, yb) + ask(xa - 1, ya - 1);
}

猜你喜欢

转载自blog.csdn.net/Floraqiu/article/details/81670493
今日推荐