• 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;
    }
    
    
  • 相关阅读:
    [LeetCode] Contains Duplicate II
    [LeetCode] House Robber II
    [LeetCode] Permutations II
    [LeetCode] Permutations
    [LeetCode] Next Permutation
    谈谈套接字
    基于Linux系统的Nagios网络管理模块的实现
    Windows/Linux下磁盘使用的图形化工具简介
    利用日志使管理Linux更轻松
    实际感受美丽的Linux(多组视频)
  • 原文地址:https://www.cnblogs.com/Yuzao/p/8733876.html
Copyright © 2020-2023  润新知