hdu 5869 - 树状数组 + 离线 + 离散(扩展)

该博客探讨了一种解题方法,涉及树状数组、离线处理和离散化技术。在处理最大值为1e6的数组a[i]时,虽然可以不离散化,但为了应对更大规模数据,作者选择了增加log(n)复杂度进行离散化。解题过程中,利用vec[i]数组存储区间右界为i的所有gcd情况及gcd的最后出现位置。通过前缀gcd个数不超过log(a[i])的性质,实现了nlog(n)的时间复杂度。在离线处理中,按查询区间的右端点r从小到大排序,更新vec[i]并确保以最右侧位置为准。

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

解题思路:首先这题a[i]值最大1e6所以可以不用考虑离散化,但是为了方便数据扩大我强行再加了一个log(n)复杂度进行数据离散化。所以现在的复杂度应该是nlog(n)*log(n),不离散的话一个log(n)就可以了。

vec[i]数组保存保存区间右界为i的所有gcd情况和该gcd最后出现的位置,那么从i位置一直向左扫gcd肯定是会越来越小的或者不变,变小的话最少变小2倍,所以一个前缀gcd个数不会超过他的log(a[i])的个数。所以我们可以用nlog(n)处理出所有位置做右边界的gcd值和他的最后出现的位置。可以采用a[i]和vec[i-1]里面的数gcd就可以得到vec[i]

离散化:在gcd过大的情况下才使用

离线:将要查询的所有区间以r从小到大排序之后,从小到大考虑。更新vec[i]里面的gcd,如果里面的gcd有出现过,取消掉之前的位置,改换为现在的位置,因为现在的位置肯定包含之前的位置了(以i为右边界那么如果j位置能考虑到,那么j右边的位置也都能取到,所以以取最右边的为准)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mx = 1e5 + 10;
int n,m,gcd[mx*18],a[mx],top,tot;
vector <pair<int,int>> vec[mx],q[mx];
//每个前缀i的gcd不同个数不会超过log(a[i]),因为gcd肯定最少是以2倍减少的 
int sum[mx],last[mx*18],ans[mx];
void add(int x,int v)
{
	while(x<=n){
		sum[x] += v;
		x += x&(-x);
	}
}
int get_sum(int x)
{
	int ans = 0;
	while(x){
		ans += sum[x];
		x -= x&(-x);
	}
	return ans;
}
int main()
{
	while(~scanf("%d%d",&n,&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值