牛客练习赛85 D.数学家的迷题(bitset暴力)

LINK


由于所有质因子只有不超过 10000 10000 10000

考虑压缩所有质因子为二进制,可以使用 b i t s e t bitset bitset来优化

这样就用线段树来维护区间 b i t s e t bitset bitset

总体复杂度为 O ( m ∗ l o g ( n ) ∗ 10000 64 ) O(m*log(n)*\frac{10000}{64}) O(mlog(n)6410000)


当然也可以手动把 10000 10000 10000个质因子分为 10000 / 50 = 200 10000/50=200 10000/50=200

维护两百颗线段树,每颗线段树维护属于自己组内的质因子,使用或运算维护区间质因子的状态

每次修改的时候,只需要去对应的线段树修改即可

总体复杂度为 O ( m ∗ 200 ∗ l o g ( n ) ) O(m*200*log(n)) O(m200log(n))

#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")


#include <bits/stdc++.h>
using namespace std;

#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid (l+r>>1)
#define lson ls,l,mid
#define rson rs,mid+1,r
const int maxn = 5e4+10;
int n,m,a[maxn],vis[maxn<<1],res,id[maxn<<1];
vector<int>vec[maxn<<1];
void as()
{
	for(int i=2;i<=100000;i++)
	{
		if( vis[i] )	{ continue; }
		id[i] = ++res;
		for(int j=i;j<=100000;j+=i)
			vec[j].push_back( i ), vis[j] = 1;
	}
}
using bs = bitset<9600>;
bs sum[maxn<<2];
bs get_bs(int x)
{
	bs temp;
	for(auto v:vec[x] )	temp.set( id[v] );
	return temp;
}
void build(int rt,int l,int r)
{
	if( l==r ){ sum[rt] = get_bs( a[l] ); return; }
	build( lson ); build( rson );
	sum[rt] = sum[ls] | sum[rs];
}
void update(int rt,int l,int r,int pos,int val)
{
	if( l==r && l==pos ){ sum[rt] = get_bs(val); return; }
	if( pos<=mid )	update( lson,pos,val );
	else update( rson,pos,val );
	sum[rt] = sum[ls] | sum[rs];
}
bs tt;
void ask(int rt,int l,int r,int L,int R)
{
	if( l>=L && r<=R )	{ tt |= sum[rt]; return; }
	if( R<=mid )	ask(lson,L,R);
	else if( L>mid )	ask(rson,L,R);
	else	{ ask(lson,L,R); ask(rson,L,R); }
}
int main()
{
	as();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)	scanf("%d",&a[i] );
	build(1,1,n);
	while( m-- )
	{
		int type,l,r; scanf("%d%d%d",&type,&l,&r);
		if( type==1 )
		{
			a[l] = r;
			update(1,1,n,l,a[l] );
		}
		else if( type==2 )
		{
			tt.reset();
			ask(1,1,n,l,r);
			printf("%d\n",tt.count() );
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值