您的位置:首页 > 其它

4298: [ONTAK2015]Bajtocja 启发式合并 hash

2016-02-26 21:09 169 查看
好题。好像get了hash的新姿势。我好弱啊。

我们可以用fi,j表示第i个图中点j所属联通块的编号,初始fi,j=j,然后每次连边时,我们可以进行启发式合并,合并的复杂度为O(dnlogn)。

如果两个点在所有图中的所属联通块编号都相同,则这两个点是联通的,我们可以hash来判一下,令hashi表示点i的hash值,是通过对数组fj,i哈希求出来的(并且为了方便我们支持加减某一位的哈希值)。如果hashi=hashj则证明i与j是联通的。我们可以对hash数组再做一次hash,用hashi and U表示hashi的哈希值,U是一个二进制下每位都是1的数,然后在得到的值下面挂一个数组模拟链表就好了。

据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]
,s[D]
,head[D]
,next[D*N*2],list[D*N*2];
ll power[D],hash
,val
;
int head_[U+1],size
,next_
,res
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: