题目描述
题解
加权并查集,每一个点的dis表示这个点的代表元素转一圈这个点转了多少圈。然后正常做。
但是有一个问题,貌似数据范围很小,但是可以发现在极限情况下是
1001000
,这就非常不好了。所以要把dis分解质因数来做。
一定要想清楚数据范围!
代码
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 1005
int T,Case,n,m,u,v,x,y;
int f[N];bool flag;
int prime[26]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97};
struct hp{int p[30];}dis[N];
void clear()
{
n=m=u=v=x=y=0;
memset(f,0,sizeof(f));
flag=false;
for (int i=1;i<=1000;++i)
for (int j=0;j<=26;++j)
dis[i].p[j]=0;
}
int Abs(int x)
{
return (x>0)?x:-x;
}
hp calc(int x)
{
hp ans;memset(ans.p,0,sizeof(ans.p));
for (int i=1;i<=25;++i)
while (x%prime[i]==0)
{
++ans.p[i];
x/=prime[i];
}
return ans;
}
hp Plus(hp a,hp b)
{
hp ans;memset(ans.p,0,sizeof(ans.p));
ans.p[0]=a.p[0]^b.p[0];
for (int i=1;i<=25;++i)
ans.p[i]=a.p[i]+b.p[i];
return ans;
}
hp Minus(hp a,hp b)
{
hp ans;memset(ans.p,0,sizeof(ans.p));
ans.p[0]=a.p[0]^b.p[0];
for (int i=1;i<=25;++i)
ans.p[i]=a.p[i]-b.p[i];
return ans;
}
bool equal(hp a,hp b)
{
for (int i=0;i<=25;++i)
if (a.p[i]!=b.p[i]) return false;
return true;
}
int find(int x)
{
if (x!=f[x])
{
int t=find(f[x]);
dis[x]=Plus(dis[x],dis[f[x]]);
f[x]=t;
}
return f[x];
}
int main()
{
scanf("%d",&T);
while (T--)
{
clear();
scanf("%d%d",&n,&m);flag=true;
for (int i=1;i<=n;++i) f[i]=i;
for (int i=1;i<=m;++i)
{
scanf("%d%d%d%d",&u,&v,&x,&y);
if (!flag) continue;
hp xx=calc(x),yy=calc(Abs(y));
if (y<0) yy.p[0]=1;
hp w=Minus(xx,yy);
int f1=find(u),f2=find(v);
if (f1!=f2)
{
hp t;
t=Minus(dis[u],dis[v]);
t=Plus(t,w);
dis[f2]=t;f[f2]=f1;
}
else
{
hp t;
t=Minus(dis[v],dis[u]);
if (!equal(t,w)) flag=false;
}
}
if (flag) printf("Case #%d: Yes\n",++Case);
else printf("Case #%d: No\n",++Case);
}
}