博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

CF 920F 区间求约数个数

题目大意

给定一个序列,支持区间每个元素变为它们的约数个数、区间求和

\(n \leq 10^5,a_i \leq 10^9\)

思路

由于\(a_i \leq 10^9\),因此每一个元素最多会被修改有限次就会变为1或2,复杂度\(O(nlogn)\)

代码

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

const int N = 3e5 + 10;
const int M = 1e6 + 10;
int a[N];
int Ans[M];
void sieve () {
	for(int i = 1;i <= M - 10; i ++) {
		for(int j = i;j <= M - 10;j += i) {
			Ans[j] ++;
		}
	}
}

struct node {
	int l,r;
	ll sum;
	int tag;
}t[N << 2];

void update(int rt) {
	int ch = rt << 1;
	t[rt].sum = t[ch].sum + t[ch + 1].sum;
	t[rt].tag = (t[ch].tag && t[ch + 1].tag);
}
void build(int l,int r,int rt) {
	t[rt].l = l;
	t[rt].r = r;
	if(l == r) {
		t[rt].sum = a[l];
		t[rt].tag = (a[l] <= 2); //是质数为1,意味着不可以继续进行分解
		return;
	}
	int mid = (l + r) >> 1;
	int ch = rt << 1;
	build(l,mid,ch);
	build(mid + 1,r,ch + 1);
	update(rt);
}


void modify(int l,int r,int rt) {
	if(t[rt].tag) return;
	if(t[rt].l == t[rt].r) {
		t[rt].sum = Ans[t[rt].sum];
		t[rt].tag = (t[rt].sum <= 2);
		return;
	}
	int mid = (t[rt].l + t[rt].r) >> 1;
	int ch = rt << 1;
	if(r <= mid) {
		modify(l,r,ch);
	}else if(l > mid) {
		modify(l,r,ch + 1);
	}else {
		modify(l,mid,ch);
		modify(mid + 1,r,ch + 1);
	}
	update(rt);
}

ll query(int l,int r,int rt) {
	if(l == t[rt].l and r == t[rt].r) return t[rt].sum;
	int mid = (t[rt].l + t[rt].r) >> 1;
	int ch = rt << 1;
	ll res = 0;
	if(r <= mid) {
		res += query(l,r,ch);
	}else if(l > mid) {
		res += query(l,r,ch + 1);
	}else {
		res += query(l,mid,ch) + query(mid + 1,r,ch + 1);
	}
	//cout << "#:" << l << ' ' << r << ' ' << res << endl;
	return res;
}

int n,m;
int main () {
	sieve();
	scanf("%d %d",&n,&m);
	for (int i = 1;i <= n; i ++) {
		scanf("%d",&a[i]);
	}
	build(1,n,1);
	while(m --) {
		int t,l,r;
		scanf("%d %d %d",&t,&l,&r);
		if(t == 1) {
			modify(l,r,1);
		}
		else {
			printf("%lld\n",query(l,r,1));
		}
	}
	return 0;
}
/*
7 6
6 4 1 10 3 2 4
2 1 7
2 4 5
1 3 5
2 4 4
1 5 7
2 1 7

*/
posted @ 2022-02-13 21:48  Allorkiya  阅读(37)  评论(0编辑  收藏  举报