Опять зима-зима-зима|

JosephusWang

园龄:2年7个月粉丝:3关注:4

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 中国大陆许可协议进行许可。

posted @   JosephusWang  阅读(7)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起