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

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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