@description@

给定d张无向图,每张图都有n个点。一开始,在任何一张图中都没有任何边。接下来有m次操作,每次操作会给出a,b,k,意为在第k张图中的点a和点b之间添加一条无向边。你需要在每次操作之后输出有序数对(a,b)的个数,使得1<=a,b<=n,且a点和b点在d张图中都连通。

Input

第一行包含三个正整数d,n,m(1<=d<=200,1<=n<=5000,1<=m<=1000000),依次表示图的个数,点的个数和操作的个数。

接下来m行,每行包含三个正整数a,b,k(1<=a,b<=n,1<=k<=d),依次描述每一个操作。

Output

输出m行m个正整数,依次表示每次操作之后满足条件的有序数对(a,b)的个数。

Sample Input

3 4 10

1 2 1

2 1 2

1 2 3

3 4 1

1 3 2

2 3 3

2 4 2

3 4 3

3 4 2

1 3 1

Sample Output

4

4

6

6

6

6

6

8

8

16

@solution@

考虑动态统计增量。

当合并两个连通块时,我们采用启发式合并的方法,将小的一个个塞进大的里面。在一个个塞的时候,统计新多出来的在 d 张图都连通的点对数量。

因为是启发式合并,每个点最多被暴力塞 log 次,所以这一部分的复杂度为 O(ndlogn)。

怎么判断两个点在 d 张图中都连通呢?因为只有加边,考虑使用并查集。

假如对于点 x 与点 y 在每张图中都有 find(x) = find(y)(find(x) 即 x 所在集合的代表元素),那么在 d 张图中 x, y 都连通。

在求点 x 与多少个点在 d 张图中都连通,即给定一个 find 序列 find(1,x), find(2,x), ..., find(d,x),求有多少个点对应的 find 序列与它相同。

判定两个序列是否相等,除了逐个比较外还可以使用字符串哈希的方法。

那么就可以通过将 find 序列给哈希了,得到的哈希值拿去找相同的值有多少个。

这个可以再写一个哈希表搞定(注意哈希表 ≠ 字符串哈希,虽然都是哈希。。。)

在合并连通块的时候,find 序列只会有一个位置发生改变,改哈希值可以 O(1) 改。

@accepted code@

#include <cstdio>
#include <vector>
#include <iostream>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ull, int> hh;
const int MAXD = 200;
const int MAXN = 5000;
const ull BASE = 13131;
const int HASHSIZE = 1000037;
vector<hh>h[HASHSIZE];
int ans;
void hash_insert(ull x) {
int hx = x % HASHSIZE;
for(int i=0;i<h[hx].size();i++)
if( h[hx][i].fi == x ) {
ans += 2*h[hx][i].se;
h[hx][i].se++;
return ;
}
h[hx].push_back(make_pair(x, 1));
}
void hash_erase(ull x) {
int hx = x % HASHSIZE;
for(int i=0;i<h[hx].size();i++)
if( h[hx][i].fi == x ) {
h[hx][i].se--;
ans -= 2*h[hx][i].se;
}
}
ull pw[MAXD + 5], hsh[MAXN + 5];
vector<int>sn[MAXD + 5][MAXN + 5];
int fa[MAXD + 5][MAXN + 5], rnk[MAXD + 5][MAXN + 5];
int find(int d, int x) {
return fa[d][x] = (fa[d][x] == x ? x : find(d, fa[d][x]));
}
void dfs(int d, int x, ull del) {
for(int i=0;i<sn[d][x].size();i++)
dfs(d, sn[d][x][i], del);
hash_erase(hsh[x]);
hsh[x] += del;
hash_insert(hsh[x]);
}
void unite(int d, int x, int y) {
x = find(d, x), y = find(d, y);
if( x == y ) return ;
if( rnk[d][x] < rnk[d][y] ) swap(x, y);
dfs(d, y, pw[d]*x - pw[d]*y);
fa[d][y] = x, sn[d][x].push_back(y);
rnk[d][x] += rnk[d][y];
}
int d, n, m;
int read() {
int x = 0; char ch = getchar();
while( ch > '9' || ch < '0' ) ch = getchar();
while( '0' <= ch && ch <= '9' ) x = 10*x + ch - '0', ch = getchar();
return x;
}
int main() {
d = read(), n = read(), m = read();
pw[1] = 1;
for(int i=2;i<=d;i++)
pw[i] = pw[i-1]*BASE;
for(int i=1;i<=d;i++)
for(int j=1;j<=n;j++) {
fa[i][j] = j, rnk[i][j] = 1;
hsh[j] += j*pw[i];
}
for(int i=1;i<=n;i++) hash_insert(hsh[i]);
for(int i=1;i<=m;i++) {
int a = read(), b = read(), k = read();
unite(k, a, b), printf("%d\n", ans + n);
}
}

@details@

读入优化真好用.jpg。

注意题目中说的是有序数对啊。

@bzoj - 4298@ [ONTAK2015]Bajtocja的更多相关文章

  1. bzoj 4298 [ONTAK2015]Bajtocja——哈希+启发式合并

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4298 题面: 给定d张无向图,每张图都有n个点.一开始,在任何一张图中都没有任何边.接下来有 ...

  2. BZOJ.4298.[ONTAK2015]Bajtocja(Hash 启发式合并)

    题目链接 \(Description\) 给定\(d\)张无向图,每张图都有\(n\)个点.一开始,在任何一张图中都没有任何边. 接下来有\(m\)次操作,每次操作会给出\(a,b,k\),意为在第\ ...

  3. 【BZOJ4298】[ONTAK2015]Bajtocja

    [BZOJ4298][ONTAK2015]Bajtocja Description 给定d张无向图,每张图都有n个点.一开始,在任何一张图中都没有任何边.接下来有m次操作,每次操作会给出a,b,k,意 ...

  4. BZOJ 4245: [ONTAK2015]OR-XOR

    4245: [ONTAK2015]OR-XOR Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 492  Solved: 269[Submit][Sta ...

  5. BZOJ 4276: [ONTAK2015]Bajtman i Okrągły Robin [线段树优化建边]

    4276: [ONTAK2015]Bajtman i Okrągły Robin 题意:\(n \le 5000\)个区间\(l,r\le 5000\),每个区间可以选一个点得到val[i]的价值,每 ...

  6. BZOJ 4278: [ONTAK2015]Tasowanie 后缀数组 + 贪心 + 细节

    Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in", "r", stdin ...

  7. BZOJ 4278: [ONTAK2015]Tasowanie (后缀数组 / 二分+hash)

    直接归并,然后如果哪边的后缀字典序比较小就去哪边,然后就可以后缀数组 博客传送门- 但是本蒟蒻不会后缀数组 Upd:Upd:Upd:现在会了233.一道差不多的题:BZOJ 1692: [Usaco2 ...

  8. BZOJ4298 : [ONTAK2015]Bajtocja

    设f[i][j]为第i张图中j点所在连通块的编号,加边时可以通过启发式合并在$O(dn\log n)$的时间内维护出来. 对于每个点,设h[i]为f[j][i]的hash值,若两个点hash值相等,则 ...

  9. bzoj 4278 [ONTAK2015]Tasowanie(SA,贪心)

    [题意] 给定两个字符串,求二路归并后最小字典序的字符串. [思路] 连接两个字符串后求出rank数组.通过比较rank数组进行二路归并. [代码] #include<cstdio> #i ...

随机推荐

  1. Veristand学习札记(3)- CD的开发

    转载:https://blog.csdn.net/mfcjishiben/article/details/79417739 1 CustomDevice开发 CD的开发必须遵照NI提供的模板进行.安装 ...

  2. Mac 安装package control

    参考网址:https://packagecontrol.io/installation 复制命令就不说明了. 主要阐述下第二种,下载安装包覆盖的方法,下面不说话,依次截图.步骤可以查看参考网址 啰嗦一 ...

  3. Thinkphp 错误集锦

    1.无法加载控制器 开始还跑TP核心文件中找错误,结果没找到什么结果.最后还是用程序新建模块才发现问题. 问题是命名空间名字写错了.比如书:本来是Report模块下的IndexContrller,但是 ...

  4. 使用 prerender 实现 SEO

    server { listen 80; server_name www.umount.com; access_log /var/log/nginx/livefrontend/access.log LF ...

  5. Java图片高保真缩放工具类

    Java图片高保真缩放 package com.xindai.auth.service.util; import java.awt.image.BufferedImage; import java.i ...

  6. centos 安装nginx + 多个tomcat负载均衡

    今天在centos上安装了两个tomcat和nginx,进行配置.今天记录的只是最基本的实现测试.(不包含使用redis进行session共享) Nginx 是一款轻量级的Web 服务器/反向代理服务 ...

  7. 洛谷P1514 [NOIP2010提高组T4]引水入城

    P1514 引水入城 题目描述 在一个遥远的国度,一侧是风景秀美的湖泊,另一侧则是漫无边际的沙漠.该国的行政区划十分特殊,刚好构成一个N 行M 列的矩形,如上图所示,其中每个格子都代表一座城市,每座城 ...

  8. 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储。

    https://github.com/kcloze/swoole-jobs 一个基于swoole的作业调度组件,已经实现了redis和rabitmq队列消息存储.参考资料:swoole https:/ ...

  9. line-height的用法(一)

    行高”顾名思意指一行文字的高度.具体来说是指两行文字间基线之间的距离. 从上到下四条线分别是顶线.中线.基线.底线,很像才学英语字母时的四线三格,我们知道vertical-align属性中有top.m ...

  10. jstree设置checkbox单选

    jstree设置插件checkbox只允许单选 jstree version console.log($.jstree.version); 3.3.8 单选配置参数: $.jstree.default ...