说在前面
me真是服气,或者me脸黑
这题Hash请用long long自然溢出不谢
反正me有一句mmp必须要讲!!
题目
题面
给定
张无向图,每张图都有
个点。一开始,在任何一张图中都没有任何边。接下来有
次操作,每次操作会给出
,意为在第
张图中的点
和点
之间添加一条无向边。你需要在每次操作之后输出有序数对
的个数,使得
,且
点和
点在
张图中都连通。
范围:
输入输出格式
输入格式:
第一行三个整数
,含义如题
接下来
行,每行一个三元组
,含义如题
输出格式:
每次操作之后,输出一行一个整数表示答案
解法
其实不难的对吧…
因为要判断多张图中,点的联通情况,保存的信息要能得出答案
不难想到使用Hash来判断,把每个点所在图与连通块哈希一下,如果两个点在所有图都联通,说明它们在每个图的联通编号都一样,这还是比较容易Hash的
然后就是维护问题了,直接用按秩合并就ok了,这样复杂度就是
关于这个Hash的问题,上面已经说了….检验你们rp的时候到了!
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int D , N , M , ans , cnt ;
long long hv[7005] , Baze = 10007 , powm[205] ;
struct Path{ int pre , to ; } ;
struct HashTable{
int head[262144] , pre[7005] , siz[7005] , que[7005] , fr , ba , tp ;
long long val[7005] ;
void init(){ fr = 1 , tp = ba = 0 ; }
void Insert( long long h ){
int id = h&262143 , t ;
for( int i = head[id] ; i ; i = pre[i] )
if( val[i] == h ){
ans += siz[i] , siz[i] ++ ;
return ;
}
if( ba != ( fr - 1 + 7005 )%7005 )t = que[fr] , fr = ( fr == 7004 ? 0 : fr + 1 ) ;
else t = ++tp ;
pre[t] = head[id] , head[id] = t ;
val[t] = h , siz[t] = 1 ;
}
void Erase( long long h ){
int id = h&262143 ;
for( int i = head[id] , las = -1 ; i ; las = i , i = pre[i] ){
if( val[i] == h ){
siz[i] -- , ans -= siz[i] ;
if( !siz[i] ){
ba = ( ba == 7004 ? 0 : ba + 1 ) , que[ba] = i ;
if( las != -1 ) pre[las] = pre[i] ;
else head[id] = pre[i] ;
} return ;
}
}
}
} Hs ;
struct Graph{
Path p[10005] ;
long long Gv ;
int fa[5005] , siz[5005] , tp , head[5005] ;
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 } ; head[t2] = tp ;
}
void init(){
cnt ++ ; powm[cnt] = powm[cnt-1] * Baze ;
Gv = powm[cnt] ;
for( int i = 1 ; i <= N ; i ++ ){
fa[i] = i , siz[i] = 1 ;
hv[i] = hv[i] + Gv * i ;
}
}
int find( int x ){ return ( fa[x] == x ? x : fa[x] = find( fa[x] ) ) ; }
void dfs( int u , int f , long long delta ){
Hs.Erase( hv[u] ) ;
hv[u] = hv[u] + Gv * delta ;
Hs.Insert( hv[u] ) ;
for( int i = head[u] ; i ; i = p[i].pre )
if( p[i].to != f ) dfs( p[i].to , u , delta ) ;
}
bool Union( int a , int b ){
a = find( a ) , b = find( b ) ;
if( a == b ) return false ;
if( siz[a] < siz[b] ) swap( a , b ) ;
dfs( b , b , a - b ) ;
In( a , b ) ;
siz[a] += siz[b] , fa[b] = a ; return true ;
}
} G[205] ;
void solve(){
for( int i = 1 , a , b , k ; i <= M ; i ++ ){
scanf( "%d%d%d" , &a , &b , &k ) ;
G[k].Union( a , b ) ;
printf( "%d\n" , ans * 2 + N ) ;
}
}
int main(){
powm[0] = 1 ;
scanf( "%d%d%d" , &D , &N , &M ) , Hs.init() ;
for( int i = 1 ; i <= D ; i ++ ) G[i].init() ;
for( int i = 1 ; i <= N ; i ++ ) Hs.Insert( hv[i] ) ;
solve() ;
}