【ONTAK2015】【BZOJ4298】Bajtocja

Description

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

第一行包含三个正整数d,n,m(1<=d<=200,1<=n<=5000,1<=m<=1000000),依次表示图的个数,点的个数和操作的个数。
接下来m行,每行包含三个正整数a,b,k(1<=a,b<=n,1<=k<=d),依次描述每一个操作。
Output

输出m行m个正整数,依次表示每次操作之后满足条件的有序数对(a,b)的个数。
Sample Input

3 4 10

1 2 1

2 1 2

1 2 3

3 4 1

1 3 2

2 3 3

2 4 2

3 4 3

3 4 2

1 3 1
Sample Output

4

4

6

6

6

6

6

8

8

16

HINT

Source

By Claris

【ONTAK2015】【BZOJ4298】Bajtocja_第1张图片

友情提示:这题卡unsigned int 的自然溢出,不卡unsigned long long的自然溢出

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 5010
#define T 210
#define U unsigned long long
#define P 793999
#define GET (ch>='0'&&ch<='9')
#define base 60383
using namespace std;
int d,n,m,top;
U Pow[T],hash[MAXN];
int ans;
void in(int &x)
{
 char ch=getchar();x=0;
 while (!GET) ch=getchar();
 while (GET) x=x*10+ch-'0',ch=getchar();
}
struct edge
{
 int to;
 U w;
 edge *next;
}e[T*MAXN<<1],*prev[T][MAXN];
void insert(int d,int u,int v)  {   e[++top].to=v;e[top].next=prev[d][u];prev[d][u]=&e[top];    }
int f[T][MAXN],size[T][MAXN];
void dfs(int d,int x,int last,int fa);
void Union(int d,int x,int y)
{
 if (f[d][x]==f[d][y]) return;
 if (size[d][f[d][x]]>size[d][f[d][y]]) swap(x,y);
 size[d][f[d][y]]+=size[d][f[d][x]];
 insert(d,x,y);insert(d,y,x);
 dfs(d,x,y,f[d][y]);
}
int Top;
struct Hash_Table
{
 U w;
 int cnt;
 Hash_Table *next;
}E[MAXN],*Prev[P+10],*sta[MAXN];
void ins(U v)
{
 U t=v%P;Hash_Table *i=Prev[t];
 for (;i;i=i->next) if (i->w==v) { ans+=(i->cnt<<1)+1;i->cnt++;return; }
 ans++;Hash_Table* j=sta[Top--];
 j->w=v;j->cnt=1;j->next=Prev[t];Prev[t]=j;
}
void del(U v)
{
 U t=v%P;Hash_Table *i=Prev[t],*j=i;
 if (i->w==v)
 {
 ans-=(i->cnt<<1)-1;
 if (!(--i->cnt)) sta[++Top]=i,Prev[t]=sta[Top]->next;
 return;
 }
 for (i=i->next;i;j=i,i=i->next)
 if (i->w==v)
 {
 ans-=(i->cnt<<1)-1;
 if (!(--i->cnt)) sta[++Top]=i,j->next=i->next;
 return;
 }
}
void dfs(int d,int x,int last,int fa)
{
 del(hash[x]);
 hash[x]-=Pow[d]*f[d][x];f[d][x]=fa;
 hash[x]+=Pow[d]*f[d][x];ins(hash[x]);
 for (edge *i=prev[d][x];i;i=i->next) if (i->to!=last) dfs(d,i->to,x,fa);
}
int main()
{
 in(d);in(n);in(m);Pow[0]=1;int u,v,w;
 for (int i=1;i<=d;i++) Pow[i]=Pow[i-1]*base;
 for (int i=1;i<=n;i++) sta[++Top]=&E[i];
 for (int i=1;i<=n;ins(hash[i++]))
 for (int j=1;j<=d;j++) f[j][i]=i,size[j][i]=1,hash[i]+=Pow[j]*i;
 while (m--)
 {
 in(u);in(v);in(w);Union(w,u,v);
 printf("%d\n",ans);
 }
}

你可能感兴趣的:(hash,并查集,启发式合并)