You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
3.1 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int N = 400010;
unordered_map<int, int> mp; // 能用Hash表不用红黑树
vector<int> p; // 将m拆分成的质数因子序列p
/*
=(+)*/2
=t,=n,=t
3,6,9 =3
(1,2,3)*3,(1,2,3)3=(1+3)*3/2*3=18
*/
int get(int t, int n) {
return n * (n + 1) / 2 * t;
}
// 容斥原理+等差数列加法和
// 求解[1,n]中与c互素的所有数字的和
// = [1,n]的数字总和 - [1,n]中所有与c存在公共因子的数的和
int calc(int n) {
int sum = get(1, n); // [1,n]的数字总和
int s = 0;
for (int i = 1; i < (1 << p.size()); i++) {
int cnt = 0, t = 1;
for (int j = 0; j < p.size(); j++) {
if (i >> j & 1) {
cnt++;
t *= p[j];
}
}
if (cnt & 1)
s += get(t, n / t);
else
s -= get(t, n / t);
}
return sum - s; // 总数,减去不互质的,等于,互质的数字加法和
}
signed main() {
#ifndef ONLINE_JUDGE
freopen("HDU4407.in", "r", stdin);
#endif
// 加快读入
ios::sync_with_stdio(false), cin.tie(0);
int T; // T组测试数据
cin >> T;
while (T--) {
mp.clear(); // 注意此处,每次测试案例都要清零
int n, m;
cin >> n >> m; // 1~n 共n 个长度的序列
while (m--) { // m个询问
int choice;
cin >> choice; // 操作
int x, y, P;
if (choice == 1) { // 查询[x,y]内与c互素的数的和
cin >> x >> y >> P;
p.clear(); /// 初始化
// 分解质因数
int t = P; // 复制出来
for (int i = 2; i * i <= t; i++) {
if (t % i == 0) {
p.push_back(i);
while (t % i == 0) t = t / i;
}
}
if (t > 1) p.push_back(t);
int sum = calc(y) - calc(x - 1); // 类似于前缀和求[x~y]区间内的等差数列加法和
// 遍历已经录入的所有修改
for (auto it = mp.begin(); it != mp.end(); it++) {
int a = it->first, b = it->second;
// 如果修改的不存本次查询的范围内,改了也不影响我,没用,不理
if (a > y || a < x) continue;
// 本来互素,结果被你改了,那就需要减掉这个数值
if (__gcd(a, P) == 1) sum -= a;
// 修改后互素的要加上新数值
if (__gcd(b, P) == 1) sum += b;
}
cout << sum << endl;
} else {
cin >> x >> P;
mp[x] = P; // 修改序列内容
}
}
}
}