1. 程式人生 > >【每日題解#10】UOJ#192. 【UR #14】最強跳蚤

【每日題解#10】UOJ#192. 【UR #14】最強跳蚤

clu for null 出現 滿足 隨機數 根節點 code hid

題目鏈接 http://uoj.ac/problem/192

暑期課第二天

樹上問題進階

具體內容看筆記博客吧

題意

n個節點的樹T 邊有邊權w 求滿足(u, v)上所有邊權乘積為完全平方數的路徑有多少條

看到“所有邊權乘積為完全平方數” 想到完全平方數的特殊性

就是分解質因數後 質因數指數都為偶數

然後就想到分解邊權質因數+判質路徑邊權奇偶性

後者由於奇數偶數的和的規律 可以使用抑或

偶就表示為0 奇就表示為一

那麽如何存儲呢?

狀壓?

空間之大 狀壓壓不下

所以hash

對每一個要用的質數 取一個 [1, 2 ^ 64] 的隨機數

出現一次就抑或一次即可

然後。。。

題意

n個節點的樹T 邊有邊權w 求滿足(u, v)上所有邊權抑或和為0的路徑有多少條

前綴和最常用的兩種 一是累加和 二是抑或和

明顯可以使用前綴和

又由於 a ^ a = 0

對於一條路徑 (路徑兩端點的lca) 到 (根節點)的那一段抑或兩次沒啦

所以如果(u, v)上所有邊權抑或和為0

那麽他們的抑或前綴和相等

以下附莫名被ex扣下3分的辣雞代碼

技術分享圖片
 1 #include <cstdio>
 2 #include <algorithm>
 3 #include <cstdlib>
 4 #include <ctime>
 5 #include <map>
 6 using namespace std;
 7 const
int N = 2e5 + 5; 8 const int M = 1e4 + 5; 9 10 int n, m; 11 struct Edge{ 12 int u, v; 13 long long w; 14 int next; 15 }edge[N << 1]; 16 int esize, head[N]; 17 long long p[M + 5], ps; 18 bool np[M]; 19 long long num[N]; 20 map<int, long long> rf; 21 22 inline void addedge(int
x, int y, long long z){ 23 edge[++esize] = (Edge){x, y, z, head[x]}; 24 head[x] = esize; 25 } 26 27 inline void p_cal(){ 28 for(int i = 2; i < M; i++){ 29 if(!np[i]) p[++ps] = i; 30 for(int j = 1; j <= ps && i * p[j] < M; j++){ 31 np[i * p[j]] = 1; 32 if(!(i % p[j])) break; 33 } 34 } 35 } 36 37 inline void build(int x, int fa){ 38 for(int i = head[x]; i != -1; i = edge[i].next){ 39 int v = edge[i].v; 40 if(v == fa) continue; 41 num[v] = num[x] ^ edge[i].w; 42 build(v, x); 43 } 44 } 45 46 int main(){ 47 srand(time(NULL)); 48 scanf("%d", &n); 49 p_cal(); 50 for(long long i = 1; i <= ps; i++) 51 rf[p[i]] = ((long long)rand() << 30) + rand(); 52 //rd續命法 53 long long res; 54 int x, y, z; 55 for(int i = 0; i <= n; i++) head[i] = -1; 56 for(int i = 1, x, y, z; i < n; i++){ 57 scanf("%d%d%d", &x, &y, &z); 58 res = 0; 59 int tmp = z; 60 for(int j = 1; j <= ps && p[j] * p[j] <= tmp; j++) 61 while(!(z % p[j])) 62 res ^= rf[p[j]], z /= p[j]; 63 if(z != 1) { 64 if(!rf[z]) 65 rf[z] = ((long long)rand() << 30) + rand(); 66 res ^= rf[z]; 67 } 68 addedge(x, y, res); addedge(y, x, res); 69 } 70 71 build(1, -1); 72 sort(num + 1, num + n + 1); 73 long long ans = 0; 74 for(int i = 1, j; i <= n; i = j){ 75 j = i; 76 while(num[j] == num[i] && j <= n) j++; 77 ans += (long long)(j - i) * (j - i - 1); 78 } 79 printf("%lld", ans); 80 return 0; 81 }
View Code

【每日題解#10】UOJ#192. 【UR #14】最強跳蚤