C 牛牛的无向图
题目地址:
基本思路:
我们考虑离线每次查询的,
在最小生成树的过程中,我们每次是从小往大加边的,
同样将也按从小到大排序,
每次加到一个比当前要大的边的时候,
之前的那些已经连上的边一定是都比小的,
所以在这些联通块中的点,两两之间的一定是比
小的,也就是符合条件的,
那么这时符合条件的点对的数量就是(
为每个联通块的大小),
每次并查集合并时维护这个结果就行了。
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false); cin.tie(0)
#define ll long long
#define SZ(x) ((int)(x).size())
#define all(x) (x).begin(), (x).end()
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF 0x3f3f3f3f
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
unsigned int SA, SB, SC; int n, m, q, LIM;
unsigned int rng61() {
SA ^= SA << 16;
SA ^= SA >> 5;
SA ^= SA << 1;
unsigned int t = SA;
SA = SB;
SB = SC;
SC ^= t ^ SA;
return SC;
}
const int maxn = 1e6 + 10;
ll u[maxn],v[maxn],w[maxn],L[maxn];
void gen() {
scanf("%d%d%d%u%u%u%d", &n, &m, &q, &SA, &SB, &SC, &LIM);
for (int i = 1; i <= m; i++) {
u[i] = rng61() % n + 1;
v[i] = rng61() % n + 1;
w[i] = rng61() % LIM;
}
for (int i = 1; i <= q; i++) {
L[i] = rng61() % LIM;
}
}
ll par[maxn],sz[maxn];
ll find(ll x){ return par[x] == x ? x : par[x] = find(par[x]); }
bool same(ll x,ll y){ return find(x) == find(y); }
struct Edge{
ll u,v,w;
bool operator < (const Edge &no) const {
return w < no.w;
}
};
vector<Edge> edge;
signed main() {
gen();
for (int i = 1; i <= n; i++) par[i] = i, sz[i] = 1;
rep(i, 1, m) edge.push_back({u[i], v[i], w[i]});
sort(L + 1, L + 1 + q);
ll pos = 1,ans = 0,res = 0;
sort(all(edge));
for (auto it : edge) {
if (!same(it.u, it.v)) {
while (it.w > L[pos] && pos <= q) { ans ^= res; pos++; }
ll x = find(it.u),y = find(it.v);
res -= sz[x] * (sz[x] - 1ll) / 2ll + sz[y] * (sz[y] - 1ll) / 2ll; // 消除要联通的这两个联通块的贡献;
par[x] = y; sz[y] += sz[x];
res += sz[y] * (sz[y] - 1ll) / 2ll;// 加上新生成的这个联通块的贡献;
}
}
rep(i,pos,q) ans ^= res;
cout << ans << '\n';
return 0;
}
京公网安备 11010502036488号