BZOJ4298 [ONTAK2015] Bajtocja
BZOJ4298 [ONTAK2015] Bajtocja
考虑给每层的每个连通块都赋予随机权值 \(key\)。记 \(val(i)\) 表示点 \(i\) 在每一层中所在连通块的权值 \(key\) 的异或和。
转化一下条件:如果 \(u,v\) 在每一层中都连通,说明每一层中 \(u,v\) 都处在相同的连通块内。
有了随机权值这一工具,上述条件可以进一步转化为 \(val(u)=val(v)\)。可以使用系统自带的哈希表维护 \(val\)。
如果需要合并两个集合,则启发式合并,维护并查集的同时维护以 \(u\) 为首的连通块内具体有哪些点,用 vector 存储。并入的结点更换了连通块,需要同时修改 \(val\) 和哈希表。
如何统计答案呢?考虑在哈希表插入或删除时同步维护,注意点对是有序的。
// Title: Bajtocja // Source: BZOJ4298 // Author: Jerrywang #include <bits/stdc++.h> #define rep(i, s, t) for(int i=s; i<=t; ++i) #define F first #define S second #define pii pair<int, int> #define ll long long #define debug(x) cout<<#x<<":"<<x<<endl; const int N=5005, M=205; using namespace std; mt19937 rnd(time(0)); int d, n, T, ans; ll val[N]; unordered_map<ll, int> mp; struct layer { int f[N]; ll key[N]; vector<int> a[N]; void init() { rep(i, 1, n) f[i]=i, key[i]=rnd()*rnd(), a[i].push_back(i); } int fa(int u) { if(u==f[u]) return u; return f[u]=fa(f[u]); } void merge(int u, int v) { u=fa(u), v=fa(v); if(u==v) return; if(a[u].size()<a[v].size()) swap(u, v); f[v]=u; for(int x:a[v]) { a[u].push_back(x); ll &t=val[x]; ans-=(--mp[t])*2; val[x]=val[x]^key[x]^key[u]; ans+=(mp[t]++)*2; key[x]=key[u]; } a[v].clear(); } } a[M]; int main() { scanf("%d%d%d", &d, &n, &T); ans=n; rep(i, 1, d) a[i].init(); rep(i, 1, n) { rep(j, 1, d) val[i]^=a[j].key[i]; mp[val[i]]++; } while(T--) { int u, v, k; scanf("%d%d%d", &u, &v, &k); a[k].merge(u, v); printf("%d\n", ans); } return 0; }
本文作者:JosephusWang
本文链接:https://www.cnblogs.com/JosephusWang/p/17857452.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步