树状数组板子

这篇博客探讨了一维和二维数组的区间修改及单点查询问题,利用树状数组(也称 BIT,Binary Indexed Tree)实现 O(logn) 复杂度的操作。内容包括逆序对的离散化计算、二维数组的区间修改与查询,并展示了如何在三维场景中应用这些算法。此外,还介绍了树状数组在求最大值问题上的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一维

ll tr[maxn];

ll lowbit(ll i)
{
    return i&(-i);
}

void update(ll x,ll v)
{
    for(ll i=x;i<=n+5;i+=lowbit(i))
    {
        tr[i]=max(tr[i],v);
    }
}

ll query(ll x)
{
    ll maxx=0;
    for(ll i=x;i>0;i-=lowbit(i))
    {
        maxx=max(maxx,tr[i]);
    }
    return maxx;
}

对A[n]分别进行如下操作m次
一维时间复杂度–O(mlogn)
二维(A[n][n])时间复杂度–O(mlognlogn)

*数组下标不能到0 *

const ll maxn = 1000 + 10;

ll c[maxn][maxn];

ll t, x, y;
ll x1, x2, y1, y2;

ll lowbit(ll i) //二进制最低位1位置
{
    return i & (-i);
}

void update(ll x, ll y, ll v) //更新(二维数组)
{
    for (ll i = x; i <=n; i += lowbit(i))//n为x轴或y轴大小,有时候随题意变化
    {
        for (ll j = y; j <=n; j += lowbit(j))
        {
            c[i][j] += v;
        }
    }
}

ll query(ll x, ll y) //查找(二维数组)
{
    ll sum = 0;
    for (ll i = x; i > 0; i -= lowbit(i))
    {
        for (ll j = y; j > 0; j -= lowbit(j)) //注意开闭区间
        {
            sum += c[i][j];
        }
    }
    return sum;
}

int main()
{
    update(x + 1, y + 1, 1); //若含有0,则坐标+1
    printf("%lld\n", query(x2 + 1, y2 + 1) - query(x2 + 1, y1) - query(x1, y2 + 1) + query(x1, y1)); //查询给定矩形区间
}

求逆序对(离散化)

ll c[maxn];
ll n,ans,a;

struct Node
{
    ll v, index;
    bool operator<(Node other) const
    {
        if(v != other.v) return v < other.v;
        else return index<other.index;//遇到存在重复元素的处理
    }
} nodes[maxn];

int main()
{
    // DEBUG;
    while (scanf("%lld", &n)!=EOF)
    {
        memset(c,0,sizeof(c));
        for (ll i = 1; i <= n; i++)
        {
            scanf("%lld", &a);
            nodes[i].index = i;
            nodes[i].v = a;//下标排序后的逆序数等于原序列逆序数
        }
        sort(nodes + 1, nodes + 1 + n);
        ans = 0;
        for (ll i = 1; i <= n; i++)
        {
            update(nodes[i].index);
            ans += i - query(nodes[i].index);//求逆序对工式
        }
        printf("%lld\n", ans);
    }
    return 0;
}

离散化(求一般形式)

for (ll i = 1; i <= n; i++)
{
    arr[nodes[i].index] = i;
}

update(arr[i]);
ans += query(arr[i]);

区间修改+单点查询

update(x1, y1,v); //二维
update(x2 + 1, y1,-v);
update(x1, y2 + 1,-v);
update(x2 + 1, y2 + 1,v);

update(x1, y1, z1,v); //三维
update(x2 + 1, y1, z1,-v);
update(x1, y2 + 1, z1,-v);
update(x1, y1, z2 + 1,-v);
update(x2 + 1, y2 + 1, z1,v);
update(x2 + 1, y1, z2 + 1,v);
update(x1, y2 + 1, z2 + 1,v);
update(x2 + 1, y2 + 1, z2 + 1,-v);

printf("%lld\n", query(x1, y1, z1) ); //查询方式

区间修改+区间查询(一维)

void update(ll x,ll v)
{
    for (ll i = x; i <maxm; i += lowbit(i))
    {
        c[i]+=v;c1[i]+=v*x;
    }
}

ll query(ll x)
{
    ll res = 0;
    for (ll i = x; i > 0; i -= lowbit(i))
    {
        res += c[i]*(x+1)-c1[i];
    }
    return res;
}

update(x,v);
update(y+1,-v);
query(r)-query(l-1);

区间修改+区间查询(二维)

void update(ll x, ll y, ll v)
{
    for (ll i = x; i <= n; i += lowbit(i))
        for (ll j = y; j <= m; j += lowbit(j))
        {
            c1[i][j] += v;
            c2[i][j] += v * x;
            c3[i][j] += v * y;
            c4[i][j] += v * x * y;
        }
}

ll query(ll x, ll y)
{
    ll res = 0;
    for (ll i = x; i > 0; i -= lowbit(i))
        for (ll j = y; j > 0; j -= lowbit(j))
        {
            res+=(x + 1) * (y + 1) * c1[i][j] - (y + 1) * c2[i][j] - (x + 1) * c3[i][j] +c4[i][j];
        }
    return res;
}

update(x1, y1, v); 
update(x2 + 1, y1, -v);
update(x1, y2 + 1, -v);
update(x2 + 1, y2 + 1, v);

query(x2 + 1, y2 + 1) - query(x2 + 1, y1) - query(x1, y2 + 1) + query(x1, y1);

树状数组求最大值

void updata(int x)
{
	int lx, i;
	while (x <= n)
	{
		h[x] = a[x];
		lx = lowbit(x);
		for (i=1; i<lx; i<<=1)
			h[x] = max(h[x], h[x-i]);
		x += lowbit(x);
	}		
}

int query(int x, int y)
{
	int ans = 0;
	while (y >= x)
	{
		ans = max(a[y], ans);
		y --;
		for (; y-lowbit(y) >= x; y -= lowbit(y))
			ans = max(h[y], ans);
	}
	return ans;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值