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。
我们可以用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; }
相关文章推荐
- [ZOJ3494]BCD Code
- Tornado开发技巧
- vector模板的用法
- Abstract(抽象)可以修饰类、方法 http://www.cnblogs.com/suneryong/p/3571362.html
- struts2学习笔记
- OpenGL入门学习(十)
- map的两种取值方式
- css中的BFC
- Hibernate inverse和cascade的作用和区别
- <LeetCode OJ> 96. Unique Binary Search Trees
- mac Zip 常用命令
- C\C++中内存分几个区
- UVALive 3026(KMP)
- Big Event in HDU (HDU_1171) 01背包
- 新手学习opencv七:svm
- MFC 程序隐藏界面
- JavaSE入门学习23:Java面向对象之构造方法
- Zookeeper集群和HBase集群
- LeetCode----Product of Array Except Self
- Python基础回顾之-变量和数据类型