Description
一棵树,给每一条边一个权值 (w_i),求出所有满足权值之积为完全平方数的路径的条数
题面
Sulotion
是完全平方数的充要条件是质因子出现次数为偶数,那么我们给每一个质因子一个随机一个权值,那么满足条件的路径就是异或和为 (0) 的路径
(dsu) 做一下就好了(别管我这个傻逼)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+10,M=1e4+10;
int n,prime[M],num=0,t[N];bool vis[M];
int head[N],nxt[N*2],to[N*2],NUM=0;
ll c[N*2],sed=41,LIM=1e15,ans=0,b[N];
inline void link(int x,int y,ll z){
nxt[++NUM]=head[x];to[NUM]=y;head[x]=NUM;c[NUM]=z;
nxt[++NUM]=head[y];to[NUM]=x;head[y]=NUM;c[NUM]=z;
}
inline void priwork(){
for(int i=2;i<M;i++){
if(!vis[i])prime[++num]=i;
for(int j=1;j<=num && i*prime[j]<M;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0)break;
}
}
}
map<int,ll>A;
inline ll seed(){return sed=(sed*41+99241)%LIM;}
inline ll F(int x){
if(A.find(x)!=A.end())return A[x];
return A[x]=seed();
}
inline ll getval(int x){
ll ret=0;
for(int i=1;i<=num;i++){
if(x<prime[i])break;
if(x%prime[i]==0){
ll w=F(prime[i]);
while(x%prime[i]==0)ret^=w,x/=prime[i];
}
}
if(x>1)ret^=F(x);
return ret;
}
int sz[N],son[N];ll dis[N];
inline void dfs1(int x){
sz[x]=1;
for(int i=head[x],u;i;i=nxt[i]){
if(sz[u=to[i]])continue;
dis[u]=dis[x]^c[i];dfs1(u);sz[x]+=sz[u];
if(sz[son[x]]<sz[u])son[x]=u;
}
}
inline void add(int x,int last){
t[dis[x]]++;
for(int i=head[x];i;i=nxt[i])if(to[i]^last)add(to[i],x);
}
inline void del(int x,int last){
t[dis[x]]=0;
for(int i=head[x];i;i=nxt[i])if(to[i]^last)del(to[i],x);
}
inline void cal(int x,int last){
ans+=t[dis[x]];
for(int i=head[x];i;i=nxt[i])if(to[i]^last)cal(to[i],x);
}
inline void dfs(int x,int last){
for(int i=head[x];i;i=nxt[i])
if(to[i]!=last && to[i]!=son[x])dfs(to[i],x),del(to[i],x);
if(son[x])dfs(son[x],x);
for(int i=head[x];i;i=nxt[i])
if(to[i]!=last && to[i]!=son[x])cal(to[i],x),add(to[i],x);
ans+=t[dis[x]];t[dis[x]]++;
}
int main(){
freopen("pp.in","r",stdin);
freopen("pp.out","w",stdout);
scanf("%d",&n);
priwork();
int x,y,z;
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&z);
link(x,y,getval(z));
}
dfs1(1);
for(int i=1;i<=n;i++)b[i]=dis[i];
sort(b+1,b+n+1);
int tp=unique(b+1,b+n+1)-b-1;
for(int i=1;i<=n;i++)dis[i]=lower_bound(b+1,b+tp+1,dis[i])-b;
dfs(1,1);
cout<<ans*2<<endl;
return 0;
}