|
|
#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; // 修改序列内容
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
} |