线段树+树状数组

这篇博客深入探讨了如何将树状数组和线段树的概念融合,以优化动态修改单点和区间查询的时间复杂度。通过实例代码展示了如何利用这种优化在动态维护数据时减少修改次数,同时分析了查询效率的变化。文章提供了详细的算法实现和应用案例,适合进阶的算法学习者参考。
摘要由CSDN通过智能技术生成

感觉这东西就是每棵线段树管的区间变了,以前学的时候线段树总是只管一个点或者管(1-i)这些点,但是这东西如果加上树状数组的思想,每棵线段树管( i-(i&-i)+1 ~ i )这些区间,那么动态修改单点就不用nlog修改只用改这个点在那log棵线段树改log*log次;查询的话变慢了点,之前的 log变成了 log * log;
精品博客 讲的真的很好 感谢大佬:
博客园 TaylorSwift13 的 树状数组套权值线段树
动态逆序对
代码

Dynamic Rankings
代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std;
typedef long long LL;
const int N = 5e5 + 4;
int n, m;
int a[N], f[N];
int rt[N], ls[N<<6], rs[N<<6], val[N<<6], idx = 0;

namespace seg
{
	void modify(int &u, int l, int r, int x, int f)
	{
		if(!u) u = ++idx;
		val[u] += f;
		if(l==r)return ;
		int mid = l+r>>1;
		x <= mid ? modify(ls[u], l, mid, x, f) : modify(rs[u], mid+1, r, x, f);
	}
	int quary(int u, int l, int r, int L, int R)
	{
		if(!u||L>r||R<l)return 0;
		if(L<=l&&R>=r)return val[u];
		int mid = l+r>>1;
		return quary(ls[u], l, mid, L, R) + quary(rs[u], mid+1, r, L, R);
	}
};

namespace tree
{
	int quary(int u, int l, int r)
	{
		int sum = 0;
		for(int x = u;x >= 1;x -= (x&-x))sum += seg::quary(rt[x], 0, n+1, l, r);
		return sum;
	}
	void modify(int u,int g, int f){for(int x = u;x <= n;x += (x&-x))seg::modify(rt[x], 0, n+1, g, f);}
};

namespace tr{
	int tr[N]={};
	void modify(int u,int f){while(u<=n+1)tr[u]+=f,u+=(u&-u);}
	int quary(int u){int sum=0;while(u)sum+=tr[u],u-=(u&-u);return sum;}
}

int main() 
{
	scanf("%d%d",&n, &m);
	for(int i = 1;i <= n;i ++)scanf("%d",a + i);
	LL ans = 0;
	for(int i = 1;i <= n;i ++)
	{
		ans += tree::quary(i-1, a[i]+1, n+1);
		tree::modify(i, a[i], 1);
		tr::modify(a[i], 1);
		f[a[i]] = i;
	}
	while(m --)
	{
		int x;
		scanf("%d", &x);	
		cout<<ans<<endl;
		ans -= tree::quary(f[x]-1, x+1, n+1);
		ans -= tr::quary(x-1) - tree::quary(f[x]-1, 0, x-1);
		tree::modify(f[x], x, -1);
		tr::modify(x, -1);
	}
	
	
	return 0;
}
#include <iostream>
#include <algorithm>
#include <cstring>
#include <sstream>
using namespace std;

typedef long long ll;
const int N = 1e5 + 4;
int n, m;
int rt[N], ls[N<<9], rs[N<<9], val[N<<9], idx;
int x[N], cntx, y[N], cnty, a[N];

int quary(int l, int r, int k)
{	
	if(l == r)return l;
	int sum = 0;
	for(int i = 0;i < cntx ;i ++)sum -= val[ls[x[i]]];
	for(int i = 0;i < cnty ;i ++)sum += val[ls[y[i]]];
	if(sum >= k)
	{
		for(int i = 0;i < cntx ;i ++)x[i] = ls[x[i]];
		for(int i = 0;i < cnty ;i ++)y[i] = ls[y[i]];
		return quary(l, l+r>>1, k);
	}
	else 
	{
		for(int i = 0;i < cntx ;i ++)x[i] = rs[x[i]];
		for(int i = 0;i < cnty ;i ++)y[i] = rs[y[i]];
		return quary((l+r>>1) + 1, r, k - sum);
	}
}

void  modify(int &u, int l, int r, int x, int f)
{
	if(!u)u = ++idx;
	val[u] += f;
	if(l == r)return ;
	int mid = l+r>>1;
	x <= mid ? modify(ls[u], l, mid, x, f) : modify(rs[u], mid+1, r, x, f);
}

int main() 
{	
	scanf("%d%d", &n, &m);
	for(int i = 1;i <= n;i ++)
	{
		scanf("%d", a+i);
		for(int u = i;u <= n;u +=(u&-u))
			modify(rt[u], 0, 1e9, a[i], 1);
	}
	while(m --)
	{
		char c[2];
		int l, r, k;
		scanf("%s%d%d", c, &l, &r);
		if(c[0]=='Q')
		{
			scanf("%d", &k);
			cntx = cnty = 0;
			for(int j = l-1;j >= 1;j -= (j&-j)) x[cntx++] = rt[j];
			for(int u = r;u >= 1; u -= (u&-u)) y[cnty++] = rt[u];
			cout<<quary(0, 1e9, k)<<endl;
		}
		else
		{
			for(int u = l;u <= n;u +=(u&-u))modify(rt[u], 0, 1e9, a[l], -1);
			a[l] = r;
			for(int u = l;u <= n;u +=(u&-u))modify(rt[u], 0, 1e9, a[l], 1);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李昌荣。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值