好题。好像get了hash的新姿势。我好弱啊。
我们可以用fi,j表示第i个图中点
如果两个点在所有图中的所属联通块编号都相同,则这两个点是联通的,我们可以hash来判一下,令hashi表示点i的
据CA爷说卡unsigned int。
#include<iostream>
#include<cstdio>
#define ll unsigned long long
#define U 262143
#define N 5005
#define D 205
using namespace std;
int fa[D][N],s[D][N],head[D][N],next[D*N*2],list[D*N*2];
ll power[D],hash[N],val[N];
int head_[U+1],size[N],next_[N],res[N];
int n,m,d,cur,ans,cnt;
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline void Addedge(int k,int x,int y)
{
next[++cnt]=head[k][x];
head[k][x]=cnt;
list[cnt]=y;
}
inline void insert(ll v)
{
int x=v&U;
for (int i=head_[x];i;i=next_[i])
if (val[i]==v)
{
ans+=2*size[i]+1;
size[i]++;
return;
}
next_[res[cur]]=head_[x]; head_[x]=res[cur]; val[res[cur]]=v; size[res[cur]]=1;
ans++; cur--;
}
inline void remove(ll v)
{
int x=v&U;
if (val[head_[x]]==v)
{
ans-=size[head_[x]]*2-1;
if (--size[head_[x]]==0) res[++cur]=head_[x],head_[x]=next_[head_[x]];
return;
}
for (int i=next_[head_[x]],j=head_[x];i;j=i,i=next_[i])
if (val[i]==v)
{
ans-=size[i]*2-1;
if (--size[i]==0) res[++cur]=i,next[j]=next[i];
return;
}
}
void dfs(int k,int x,int f,int ff)
{
remove(hash[x]);
hash[x]-=power[k]*fa[k][x];
fa[k][x]=ff;
hash[x]+=power[k]*fa[k][x];
insert(hash[x]);
for (int i=head[k][x];i;i=next[i])
if (list[i]!=f) dfs(k,list[i],x,ff);
}
inline void unite(int k,int x,int y)
{
if (fa[k][x]==fa[k][y]) return;
if (s[k][fa[k][x]]>s[k][fa[k][y]]) swap(x,y);
s[k][fa[k][y]]+=s[k][fa[k][x]];
Addedge(k,x,y); Addedge(k,y,x);
dfs(k,x,y,fa[k][y]);
}
int main()
{
d=read(); n=read(); m=read(); power[0]=1;
for (int i=1;i<=d;i++) power[i]=power[i-1]*2333;
for (int i=1;i<=n;i++) res[++cur]=i;
for (int i=1;i<=n;i++)
{
for (int j=1;j<=d;j++)
fa[j][i]=i,s[j][i]=1,hash[i]+=power[j]*i;
insert(hash[i]);
}
for (int i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
unite(w,u,v);
printf("%d\n",ans);
}
return 0;
}