@bzoj - 4298@ [ONTAK2015]Bajtocja
@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的更多相关文章
- bzoj 4298 [ONTAK2015]Bajtocja——哈希+启发式合并
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4298 题面: 给定d张无向图,每张图都有n个点.一开始,在任何一张图中都没有任何边.接下来有 ...
- BZOJ.4298.[ONTAK2015]Bajtocja(Hash 启发式合并)
题目链接 \(Description\) 给定\(d\)张无向图,每张图都有\(n\)个点.一开始,在任何一张图中都没有任何边. 接下来有\(m\)次操作,每次操作会给出\(a,b,k\),意为在第\ ...
- 【BZOJ4298】[ONTAK2015]Bajtocja
[BZOJ4298][ONTAK2015]Bajtocja Description 给定d张无向图,每张图都有n个点.一开始,在任何一张图中都没有任何边.接下来有m次操作,每次操作会给出a,b,k,意 ...
- BZOJ 4245: [ONTAK2015]OR-XOR
4245: [ONTAK2015]OR-XOR Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 492 Solved: 269[Submit][Sta ...
- 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]的价值,每 ...
- BZOJ 4278: [ONTAK2015]Tasowanie 后缀数组 + 贪心 + 细节
Code: #include <bits/stdc++.h> #define setIO(s) freopen(s".in", "r", stdin ...
- BZOJ 4278: [ONTAK2015]Tasowanie (后缀数组 / 二分+hash)
直接归并,然后如果哪边的后缀字典序比较小就去哪边,然后就可以后缀数组 博客传送门- 但是本蒟蒻不会后缀数组 Upd:Upd:Upd:现在会了233.一道差不多的题:BZOJ 1692: [Usaco2 ...
- BZOJ4298 : [ONTAK2015]Bajtocja
设f[i][j]为第i张图中j点所在连通块的编号,加边时可以通过启发式合并在$O(dn\log n)$的时间内维护出来. 对于每个点,设h[i]为f[j][i]的hash值,若两个点hash值相等,则 ...
- bzoj 4278 [ONTAK2015]Tasowanie(SA,贪心)
[题意] 给定两个字符串,求二路归并后最小字典序的字符串. [思路] 连接两个字符串后求出rank数组.通过比较rank数组进行二路归并. [代码] #include<cstdio> #i ...
随机推荐
- k8s(openshift) 部署istio1.1
准备工作: openshift 默认不允许UID为0的容器运行,要先授权scc以便安装istio # oc adm policy add-scc-to-user anyuid -z istio-ing ...
- 前端插件--isCroll的使用
中文文档地址: http://wiki.jikexueyuan.com/project/iscroll-5/ 效果图: <!DOCTYPE html> <html lang=&quo ...
- 组合数学起步-排队[HNOI2012][BZOJ2729]
<题面> 这个题十分基础 写这个博客给自己看的呵呵 遇到这个题,一看就是组合数学, so,开始推公式, 刚开始想的是,先排男生,再排女生,最后排老师 推了一会,呃呃呃,情况复杂,考虑的好像 ...
- SPSS详细操作:样本均数间的多重比较
SPSS详细操作:样本均数间的多重比较 下面我们用例子来探讨:方差分析得出各组总体均数间的差异有统计学意义之后,如何进行样本均数间的多重比较. 一.问题与数据 为调查A.B.C三种治疗措施对患者谷丙转 ...
- python基础--反射、元类、单例设计模式
反射:reflect,反射指的是一个对象应该具备可以检测.修改.增加自身属性的能力,反射就是通过字符串操作属性 hasattr(对象,带查询的属性名称) 判断某个对象中是否存在某个属性 getattr ...
- python无法启动火狐浏览器且报错“selenium.common.exceptions.WebDriverException: Message: Unable to find a matching set of capabilities”
安装了python2,使用pip安装了selenium,但是在使用时,报了“selenium.common.exceptions.WebDriverException: Message: 'gecko ...
- 【风马一族_win10设置热点】win10无法开启热点怎么办
输入cmd,设置管理员开启 输入netsh wlan set hostednetwork mode=allow ssid=name(无线名字) key=00000000(8位以上密码); 输入nets ...
- CURL POST PHP
function SendPostCurl($url,$post_data){ $curl = curl_init(); //初始化 curl_setopt($curl, CURLOPT_URL, $ ...
- linux常用目录介绍
bin:全称binary,含义是二进制,该目录中存放的都是一些二进制文件,这些文件都是可以被运行的. dev:该目录主要存放的是外接设备,例如:光盘等.注意:在其中的设备是不能被直接使用的,需要挂载( ...
- sublime3安装javascript控制台环境 方法2
1.下载node.js sublimeText3- 安装nodejs插件 ctrl+shift+p — install package —nodejs 2.修改配置文件 在 Sublie Text ...