UOJ #192. 【UR #14】最强跳蚤

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;
}

转载于:https://www.cnblogs.com/Yuzao/p/8733876.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值