題目鏈接
problem
給出一個n個點帶邊權的樹,問有多少對\((u,v)\)滿足\(u\)到\(v\)路徑上邊權的乘積為完全平方數,
\(n\le 10^5,w\le 10^8\)
solution
一個比較樸素的處理方法就是:設第i個質因子權值為\(2^{i-1}\),將每個邊權質因子分解,并將所有質因子的權值異或起來,然后得到一個新的權值,這樣問題就轉化為了求有多少對\((u,v)\)滿足從\(u\)到\(v\)路徑上的權值異或和為0,直接書上前綴和一下就行,
但是當\(w=10^8\)時顯然不行,考慮給每個質因子隨機賦一個\([0,2^{64}]\)中的值,然后用同樣的方法異或起來,這樣滿足條件的路徑一定可以被找到,不滿足條件的路徑只有\(\frac{1}{2^{64}}\)誤算,
然后考慮如何計算每個數字的質因子,先線性篩出\([1,\sqrt{w}]\)中的質因子,并對其重新賦權值,對于大于\(\sqrt{w}\)的質因子單獨處理一下,
code
/*
* @Author: wxyww
* @Date: 2020-02-05 16:57:50
* @Last Modified time: 2020-02-05 18:21:14
*/
#include<map>
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 100010;
ll read() {
ll x=0,f=1;char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
struct node {
int v,nxt;ull w;
}e[N << 1];
int head[N],ejs;
void add(int u,int v,ull w) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;e[ejs].w = w;
}
map<int,ull>ma;
ull Rand() {
return (ull)rand() * (ull)rand() * (ull)rand() * (ull)rand() * (ull)rand();
}
ull val[N];
int vis[N],pri[N],tot;
void pre() {
for(int i = 2;i <= 10000;++i) {
if(!vis[i]) {
pri[++tot] = i;
val[tot] = Rand();
}
for(int j = 1;j <= tot && i * pri[j] <= 10000;++j) {
vis[pri[j] * i] = 1;
if(i % pri[j] == 0) break;
}
}
}
ull get(int x) {
ull ret = 0;
for(int i = 1;i <= tot;++i) {
while(x % pri[i] == 0) {
x /= pri[i];
ret ^= val[i];
}
}
if(x != 1) {
if(!ma.count(x)) ma[x] = Rand();
ret ^= ma[x];
}
return ret;
}
ull dis[N];
ll anss;
map<ull,int>ans;
void dfs(int u,int fa) {
anss += ans[dis[u]] * 2;
ans[dis[u]]++;
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;if(v == fa) continue;
dis[v] = dis[u] ^ e[i].w;
dfs(v,u);
}
}
int main() {
pre();
int n = read();
for(int i = 1;i < n;++i) {
int u = read(),v = read();ull w = get(read());
add(u,v,w);add(v,u,w);
}
dfs(1,0);
cout<<anss;
return 0;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/69154.html
標籤:C++
