#include using namespace std; #define int long long #define endl "\n" const int N = 400010; unordered_map mp; // 能用Hash表不用红黑树 vector 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; // 修改序列内容 } } } }