問題の意味
これは、二部グラフ、両側のn個の点のそれぞれ、m個のエッジの総数、N、M≤5E5を与える。重量のドットの右\(C_I \)を Sだけ左点を含む点集合、Nの定義(のために、 S)右に隣接する全てのこのセットポイント設定点の点であり、F(S)は、すべての可能なF(S)は、最大公約数であり、これらの点およびQの重量です。
思考
彼らは、ポイントに元の重量と重量の新しい値を縮小するように、それらはN(S)で同時に発生しなければならないことを示し、それらが一致している点に対応する左場合は、右側の点の数を考慮する。凝縮を点0度に再びそれらの点を除去した後、次の証明GCD答えは残りの点の重みである。後述する(C_I \)\上述した処理されました。
このとき、答えは、配置されたグラムであるGの真の価値を与えることを、明らかにG.すべてのF(S)で割り切れる答え\(G | G \)を提供する。\(Gは\ G×K =)ので、すべてのこと。\(C_I \ )で割った\(G \) 。仮定>(\ Kを1に\)がある\(C_J \) 、そう\(K \ C_J NMID \) 、ポイントの全てに隣接して配置された点を構成しません集合S「U、N(S放置ポイントの全集」)は、他のポイントがない場合ので、ポイントがあるため、矛盾している縮小された、含まれるだけでなく、右の点セット点j含まれる\ (K | F(U-)、K \ C_J NMID \) 、そう\(K \ NMID F(U - S「)\) 、競合解決ように。\(K = 1、G = G \。) 。
コード
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inc(i, l, r) for (int i = l; i <= r; i++)
const int maxn = 5e5 + 5;
int t, n, m, u, v;
ll c[maxn];
vector<int> g[maxn];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> t;
while (t--) {
cin >> n >> m;
inc(i, 0, n - 1) vector<int>().swap(g[i]);
inc(i, 0, n - 1) cin >> c[i];
inc(i, 0, m - 1) {
cin >> u >> v;
u--, v--;
g[v].push_back(u);
}
inc(i, 0, n - 1) sort(g[i].begin(), g[i].end());
vector<int> id(n);
iota(id.begin(), id.end(), 0);
sort(id.begin(), id.end(), [&](int a, int b) { return g[a] < g[b]; });
ll res = 0;
for (int i = 0, j; i < n; i = j) {
ll sum = 0;
j = i;
while (j < n && g[id[i]] == g[id[j]]) {
sum += c[id[j]];
j++;
}
if (g[id[i]].size()) res = __gcd(res, sum);
}
cout << res << "\n";
}
}