zoukankan      html  css  js  c++  java
  • BZOJ.4298.[ONTAK2015]Bajtocja(Hash 启发式合并)

    题目链接

    (Description)

    给定(d)张无向图,每张图都有(n)个点。一开始,在任何一张图中都没有任何边。
    接下来有(m)次操作,每次操作会给出(a,b,k),意为在第(k)张图中的点(a)和点(b)之间添加一条无向边。
    你需要在每次操作之后输出有序数对((a,b))的个数,满足(1leq a,bleq n),且(a)点和(b)点在(d)张图中都连通。
    (dleq 200,nleq 5000,mleq 1000000)

    (Solution)

    我们需要知道的只是每对点之间是否连通,即在同一张图所属的连通块是否一样
    于是我们对每个点在d张图中所属的连通块标号进行哈希,这个哈希要能快速删除一个标号 插入一个标号
    如果有两个点哈希后的值相同,那么这两个点在d张图中都连通。于是我们再对这个哈希值做一遍哈希,来计算相同哈希值的个数
    连边时用启发式合并,每次将size小的连通块全部修改fa,总复杂度(O(dnlog n))

    //75500kb	4628ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    #define gc() getchar()
    typedef unsigned long long ull;
    const int N=5005,D=205,M=1e6+5,mod=2e6;
    const ull seed=769;
    
    int n,m,d,H[D][N],Enum,to[M<<1],nxt[M<<1],fa[D][N],sz[D][N],Ans;
    ull hs_id[N],Pow[D];
    struct Hash_Table
    {
    	int top,h_H[mod+5],sk[mod],h_nxt[mod],cnt[mod];
    	ull val[mod];
    	void Init()
    	{
    		top=mod-5;
    		for(int i=1; i<=top; ++i) sk[i]=i;
    	}
    	void Insert(ull x)
    	{
    		int p=x%mod;
    		for(int i=h_H[p]; i; i=h_nxt[i])
    			if(val[i]==x) {Ans+=2*cnt[i]+1,++cnt[i]; return;}
    		++Ans;//(a,a)也算一对 
    		int pos=sk[top--];
    		val[pos]=x, cnt[pos]=1, h_nxt[pos]=h_H[p], h_H[p]=pos;
    	}
    	void Delete(ull x)
    	{
    		int p=x%mod,pre=h_H[p];
    		if(val[pre]==x)
    		{
    			Ans-=2*cnt[pre]-1;
    			if(!--cnt[pre]) sk[++top]=pre, h_H[p]=h_nxt[pre];
    		}
    		else
    			for(int i=h_nxt[pre]; i; pre=i,i=h_nxt[i])
    				if(val[i]==x)
    				{
    					Ans-=2*cnt[i]-1;
    					if(!--cnt[i]) sk[++top]=i, h_nxt[pre]=h_nxt[i];
    					break;
    				}
    	}
    }hs2;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline void AddEdge(int u,int v,int k){
    	to[++Enum]=v, nxt[Enum]=H[k][u], H[k][u]=Enum;
    }
    void DFS(int x,int f,int k,int anc)
    {
    	hs2.Delete(hs_id[x]);
    	hs_id[x]-=Pow[k]*fa[k][x];//fa就是belong了 
    	fa[k][x]=anc;
    	hs_id[x]+=Pow[k]*anc;
    	hs2.Insert(hs_id[x]);
    	for(int i=H[k][x]; i; i=nxt[i])
    		if(to[i]!=f) DFS(to[i],x,k,anc);
    }
    void Union(int u,int v,int k)
    {
    	if(fa[k][u]==fa[k][v]) return;
    	if(sz[k][fa[k][u]]<sz[k][fa[k][v]]) std::swap(u,v);
    	sz[k][fa[k][u]]+=sz[k][fa[k][v]];
    	DFS(v,u,k,fa[k][u]);
    	AddEdge(u,v,k),AddEdge(v,u,k);
    }
    
    int main()
    {
    	d=read(),n=read(),m=read();
    	Pow[0]=1;
    	for(int i=1; i<D; ++i) Pow[i]=Pow[i-1]*seed;
    	hs2.Init();
    	for(int i=1; i<=n; hs2.Insert(hs_id[i++]))
    		for(int j=1; j<=d; ++j)
    			fa[j][i]=i, sz[j][i]=1, hs_id[i]+=Pow[j]*i;//Hash = (∑s[i]seed^i) mod 2^{31}
    	int a,b,k;
    	while(m--)
    		a=read(),b=read(),k=read(),Union(a,b,k),printf("%d
    ",Ans);
    	return 0;
    }
    
  • 相关阅读:
    Bootstrap 2.2.2 的新特性
    Apache POI 3.9 发布,性能显著提升
    SQL Relay 0.48 发布,数据库中继器
    ProjectForge 4.2.0 发布,项目管理系统
    红帽企业 Linux 发布 6.4 Beta 版本
    红薯 快速的 MySQL 本地和远程密码破解
    MariaDB 宣布成立基金会
    Percona XtraBackup 2.0.4 发布
    Rocks 6.1 发布,光盘机群解决方案
    精通Servlet研究,HttpServlet的实现追究
  • 原文地址:https://www.cnblogs.com/SovietPower/p/8504020.html
Copyright © 2011-2022 走看看