typedeflonglong ll; constint N = 1e5+10; constint P = 1e9+7; constint A = 1e5;
namespace sieve { bool vis[N]; int prime[N], pcnt; ll mu[N]; voidmain() { mu[1] = 1; for(int i = 2; i <= A; i++) { if(!vis[i]) prime[++pcnt] = i, mu[i] = -1; for(int j = 1; j <= pcnt and i*prime[j] <= A; j++) { vis[i*prime[j]] = true; if(i%prime[j] == 0) break; else mu[i*prime[j]] = -mu[i]; } } } } namespace bit { ll a[N]; #define lowbit(i) (i&-i) voidadd(int x, ll v){ for(; x <= A; x += lowbit(x)) (a[x] += v) %= P; } ll get(int x){ ll ans = 0; for(; x >= 1; x -= lowbit(x)) (ans += a[x]) %= P; return ans; } ll get(int l, int r){ return (get(r)-get(l-1)+P)%P;} }
usingnamespace bit; usingnamespace sieve;
int tot; ll ans[N]; structquery {int n, m, a, id; } q[N];
ll solve(int n, int m); ll S(ll x){ return x*(x+1)/2%P; }
intmain() { sieve::main(); read(tot); for(int i = 1; i <= tot; i++) read(q[i].n, q[i].m, q[i].a), q[i].id = i; sort(q+1, q+tot+1, [&](query a, query b){ return a.a < b.a; }); int d = 0; for(int i = 1; i <= tot; i++) { while(d < q[i].a) { d++; for(ll T = d; T <= A; T += d) bit::add(T, T*T/d%P * (mu[T/d]+P)%P); } ans[q[i].id] = solve(q[i].n, q[i].m); } for(int i = 1; i <= tot; i++) print(ans[i], '\n'); }
ll solve(int n, int m) { if(n > m) swap(n, m); ll sum = 0; for(int l = 1, r; l <= n; l = r+1) { r = min(n/(n/l), m/(m/l)); sum += bit::get(l, r) * S(n/l)%P * S(m/l)%P; sum %= P; } return sum; }
int n, q, cnt; // cnt是面的数量 int belong[N], num; // 原图上每个点所属的连通块 int cur[N]; bool vis[N]; map<pir, int> mp; // (x,y) 在 ver[x] 中的编号 (ver[x]按顺时针排序) map<pir, int> id; // 每条边所属的面 vector<int> ver[N];
namespace dsu { int f[N*10]; voidinit(int n){ for(int i = 1; i <= n; i++) f[i] = i; } intfind(int x){ return f[x] == x ? x : f[x] = find(f[x]); } inlinevoidmerge(int x, int y){ f[find(y)] = find(x); } inlineboolcheck(int x, int y){ returnfind(x) == find(y); } }
voidtoggle(int x, int pre, int st); boolextend(vector<int> &v, int &st);
intmain() { read(n, q); for(int x = 1; x <= n; x++) { int k; read(k); for(int i = 1; i <= k; i++) { int y; read(y); ver[x].push_back(y); mp[{x,y}] = i-1; } } for(int x = 1; x <= n; x++) { for(auto y : ver[x]) { if(id.count({x,y})) continue; id[{x,y}] = ++cnt; toggle(y, x, x); } } for(int x = 1; x <= n; x++) sort(ver[x].begin(), ver[x].end()); dsu::init(cnt); char opt; int x, y; int tot = 1, lastans = 0; for(int i = 1; i <= q; i++) { read(opt, x, y); x ^= lastans; y ^= lastans; if(opt == '-') { int a = id[{x,y}], b = id[{y,x}]; ver[x].erase(lower_bound(ver[x].begin(), ver[x].end(), y)); ver[y].erase(lower_bound(ver[y].begin(), ver[y].end(), x)); if(dsu::check(a, b)) { tot++; vector<int> v1, v2; int p1 = 0, p2 = 0; v1.push_back(x); v2.push_back(y); while(true) { if(!extend(v1, p1)) { num++; for(auto i : v1) belong[i] = num; break; } if(!extend(v2, p2)) { num++; for(auto i : v2) belong[i] = num; break; } } for(auto i : v1) cur[i] = vis[i] = 0; for(auto i : v2) cur[i] = vis[i] = 0; } else dsu::merge(a, b); print(lastans = tot, '\n'); } else print(lastans = (belong[x]==belong[y]), '\n'); } }
voidtoggle(int x, int pre, int st) { if(x == st) returnvoid(); int p = mp[{x,pre}]; p = (p+1)%ver[x].size(); // 顺时针的下一条边 int y = ver[x][p]; id[{x,y}] = cnt; toggle(y, x, st); }
boolextend(vector<int> &v, int &st) { for(; st < v.size(); st++) { int x = v[st]; for(int i = cur[x]; i < ver[x].size(); cur[x] = ++i) { int y = ver[x][i]; if(!vis[y]) { vis[y] = true; v.push_back(y); returntrue; } } } returnfalse; }