A:Martadella Stikes Againnode
水。c++
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define ll long long 6 7 int t; 8 ll R, r; 9 10 int main() 11 { 12 scanf("%d", &t); 13 while (t--) 14 { 15 scanf("%lld%lld", &R, &r); 16 if (R * R > 2ll * r * r) 17 puts("1"); 18 else 19 puts("2"); 20 } 21 return 0; 22 }
B:Amer and Graphsdom
題意:給出n條邊,連續選k條邊,(1 <= k <= n) 對於每個圖,有多少個圖和它同樣ide
思路:圖Hash,枚舉起點,再枚舉長度,這樣每次加邊都是一條,時間複雜度O(n ^ 2)ui
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define INF 0x3f3f3f3f 5 #define INFLL 0x3f3f3f3f3f3f3f3f 6 #define ll long long 7 #define N 2003 8 9 typedef pair <int, int> pii; 10 11 struct simplehash 12 { 13 int len; 14 ll base, mod; 15 vector <ll> P, H; 16 17 inline simplehash() {} 18 inline simplehash(const int *ar, int n, ll b, ll m) 19 { 20 len = n; base = b, mod = m; 21 P.resize(len + 3, 1); H.resize(len + 3, 0); 22 for (int i = 1; i <= len; ++i) P[i] = (P[i - 1] * base) % mod; 23 for (int i = 1; i <= len; ++i) H[i] = (H[i - 1] + P[ar[i]]) % mod; 24 } 25 26 inline ll range_hash(int l, int r) 27 { 28 ll hashval = (H[r] - H[l - 1]) % mod; 29 return (hashval < 0 ? hashval + mod : hashval); 30 } 31 }; 32 33 struct arrayhash 34 { 35 simplehash sh1, sh2; 36 inline arrayhash() {} 37 inline arrayhash(const int *ar, int n) 38 { 39 sh1 = simplehash(ar, n, 1949313259, 2091573227); 40 sh2 = simplehash(ar, n, 1997293877, 2117566807); 41 } 42 inline ll range_hash(int l, int r) 43 { 44 return (sh1.range_hash(l, r) << 32) ^ (sh2.range_hash(l, r)); 45 } 46 }; 47 48 int t, n, pos; 49 map <pii, int> mp; 50 unordered_map <ll, int> mp2; 51 int arr[N]; 52 53 inline void Init() 54 { 55 mp.clear(); pos = 0; 56 mp2.clear(); 57 } 58 59 struct Edge 60 { 61 int u, v, id; 62 inline void scan() 63 { 64 scanf("%d%d", &u, &v); 65 if (u > v) swap(u, v); 66 if (!mp.count(pii(u, v))) 67 mp[pii(u, v)] = mp.size() + 1; 68 id = mp[pii(u, v)]; 69 } 70 }edge[N]; 71 72 inline void Run() 73 { 74 scanf("%d", &t); 75 while (t--) 76 { 77 scanf("%d", &n); Init(); 78 for (int i = 1; i <= n; ++i) 79 { 80 edge[i].scan(); 81 arr[i] = edge[i].id; 82 } 83 ll ans = 0; 84 arrayhash x = arrayhash(arr, n); 85 for (int i = 1; i <= n; ++i) 86 { 87 for (int j = i; j <= n; ++j) 88 { 89 ll Hash = x.range_hash(i, j); 90 ans += mp2[Hash]++; 91 } 92 } 93 printf("%lld\n", ans); 94 } 95 } 96 97 int main() 98 { 99 #ifdef LOCAL 100 freopen("Test.in", "r", stdin); 101 #endif 102 103 Run(); 104 105 return 0; 106 }
C:Help Shahhoudspa
題意:給出A串和B串,每次能夠翻轉以A串中心點爲軸,翻轉長度爲x,求長度最少使得串A變成串B,若是不行輸出-1設計
思路:很顯然要從外往裏翻,若是某一段翻轉性質相同,那麼能夠一併翻轉,要特別考慮一下四個字符都相同,那麼既能夠翻轉既能夠不翻轉3d
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 int t; 8 char A[N]; 9 char B[N]; 10 11 int main() 12 { 13 scanf("%d",&t); 14 while(t--) 15 { 16 scanf("%s", A + 1); 17 scanf("%s", B + 1); 18 int len = strlen(A + 1); 19 int ans = 0; 20 int flag = 0; 21 for(int i = 1; i <= len / 2; ++i) 22 { 23 int l = i, r = len - i + 1; 24 if(A[l] == A[r] && A[l] == B[r] && B[l] == B[r]) continue; 25 else if(A[l] == B[r] && A[r] == B[l]) 26 { 27 if(flag == 0) 28 { 29 ++ans; 30 flag = !flag; 31 } 32 } 33 else if(A[l] == B[l] && A[r] == B[r]) 34 { 35 if(flag == 1) 36 { 37 ++ans; 38 flag = !flag; 39 } 40 } 41 else 42 { 43 ans = -1; 44 break; 45 } 46 } 47 if(A[(len + 1) / 2] != B[(len + 1) / 2]) ans = -1; 48 printf("%d\n",ans); 49 } 50 return 0; 51 }
D:Simplified 2048code
留坑。blog
E:Floods
題意:給出n個點造成山地(折線圖),在下過一段時間的雨後留下的雨量。
思路:顯然只有凹下去的點才能作出貢獻。因此能夠分爲如下幾種狀況。一種是圖中一部分,一種是圖中二部分。對於一部分即求一個梯形面積,對於第二部分即求一個三角形的類似三角形的面積,累加一下便可。
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 struct node{ 8 int x,y; 9 inline node(){} 10 inline node(int x,int y) :x(x),y(y){} 11 }a[N]; 12 13 int L[N]; 14 int R[N]; 15 int n; 16 17 int main() 18 { 19 int t; 20 scanf("%d",&t); 21 while(t--) 22 { 23 scanf("%d",&n); 24 for(int i = 1; i <= n; ++i) 25 { 26 scanf("%d %d",&a[i].x,&a[i].y); 27 } 28 int Max = 0; 29 for(int i = 1; i <= n; ++i) 30 { 31 Max = max(Max,a[i].y); 32 L[i] = Max; 33 } 34 Max = 0; 35 for(int i = n; i >= 1; --i) 36 { 37 Max = max(Max, a[i].y); 38 R[i] = Max; 39 } 40 double ans = 0; 41 for(int i = 1; i < n; ++i) 42 { 43 int top, Max, Min; 44 if(a[i].y < a[i + 1].y) 45 { 46 top = min(L[i], R[i]); 47 Max = a[i + 1].y; 48 Min = a[i].y; 49 } 50 else 51 { 52 top = min(L[i + 1], R[i + 1]); 53 Max = a[i].y; 54 Min = a[i + 1].y; 55 } 56 if(top >= Max) 57 { 58 ans += (double)(a[i + 1].x - a[i].x) * (top - a[i].y + top - a[i + 1].y) * 0.5; 59 } 60 else if(top > Min) 61 { 62 ans += (double)(a[i + 1].x - a[i].x) * (top - Min) * (top - Min) / (Max - Min) * 0.5; 63 } 64 } 65 printf("%.8f\n",ans); 66 } 67 return 0; 68 }
F:Random Sort
題意:給出n個數,對標號全排列,看有多少種排列裏面的數是排好的
思路:若是有相同的數,那麼對於這個數它的貢獻是fac[x] (fac是階乘,x是個數)
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 const int MOD = 7901; 6 7 #define N 1010 8 9 int inv[N]; 10 int n; 11 int a[N]; 12 13 int main() 14 { 15 inv[0] = 1; 16 for(int i = 1; i < N; ++i) 17 { 18 inv[i] = inv[i - 1] * i % MOD; 19 } 20 int t; 21 scanf("%d",&t); 22 while(t--) 23 { 24 scanf("%d",&n); 25 int ans = 1; 26 for(int i = 1; i <= n; ++i) 27 { 28 scanf("%d",&a[i]); 29 } 30 sort(a + 1, a + 1 + n); 31 int cnt = 1; 32 for(int i = 2;i <= n; ++i) 33 { 34 if(a[i - 1] == a[i]) 35 { 36 cnt++; 37 } 38 else 39 { 40 ans = ans * inv[cnt] % MOD; 41 cnt = 1; 42 } 43 } 44 ans = ans * inv[cnt] % MOD; 45 printf("%d\n",ans); 46 } 47 return 0; 48 }
G:Weird Requirements
題意:給出n個數,修改最少的數字,使得gcd=x,lcm=y。
思路:顯然,一個數的因數不包括gcd和lcm的因數是必定要修改的。統計這些數字的個數。當剩下的數字的因數都知足gcd與lcm的因數的時候,顯然最多修改兩個數字。那麼當一定修改的數的個數大於等於2的時候輸出這個數字便可。對於剩下的數字,求出他們的gcd與lcm。那麼y/gcd爲須要增長的因數,lcm/x爲須要減小的因數,可是當增長的因數和減小的因數的gcd!=1時須要修改兩個數字。例如gcd=6,lcm=24,五個數分別爲12 12 12 12 14
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 #define N 100010 6 7 typedef long long ll; 8 9 int t, n; 10 ll arr[N]; 11 ll x, y; 12 13 inline ll GCD(ll a, ll b) 14 { 15 return b == 0 ? a : GCD(b, a % b); 16 } 17 18 int main() 19 { 20 scanf("%d", &t); 21 while (t--) 22 { 23 scanf("%d", &n); 24 scanf("%lld%lld", &x, &y); 25 for (int i = 1; i <= n; ++i) scanf("%lld", arr + i); 26 if (y % x) 27 { 28 puts("-1"); 29 continue; 30 } 31 if(n == 1 && x != y) 32 { 33 puts("-1"); 34 continue; 35 } 36 int ans = 0; 37 ll gcd = y, lcm = x; 38 for (int i = 1; i <= n; ++i) 39 { 40 if(arr[i] % x || y % arr[i]) ++ans; 41 else 42 { 43 gcd = GCD(gcd, arr[i]); 44 lcm = lcm * arr[i] / GCD(lcm, arr[i]); 45 } 46 } 47 if (ans >= 2) 48 printf("%d\n", ans); 49 else if(ans == 1) 50 { 51 if(gcd != x && lcm != y && GCD(y / gcd, lcm / x) != 1) 52 { 53 puts("2"); 54 } 55 else 56 { 57 puts("1"); 58 } 59 } 60 else 61 { 62 if(x == gcd && y == lcm) 63 { 64 puts("0"); 65 } 66 else if(x != gcd && y != lcm && GCD(x / gcd, lcm / y) != 1) 67 { 68 puts("2"); 69 } 70 else 71 { 72 puts("1"); 73 } 74 } 75 } 76 return 0; 77 }
H:Shahhoud the Chief Judge
題意:一棵樹,每一個點有權值,sum = sgm(每一個點的權值 * 路徑通過它的次數)
思路:設cnt[i] 表示通過第i個點的路徑數,若是存在gcd(cnt[i], cnt[j]) == 1 ,那麼經過i, j 這兩個數,就能夠構造出全部的整數
裴蜀定理: ax + by = cgcd(a,b); c爲任意整數,當gcd(a, b)==1 時 cgcd(a, b) 爲任意整數
在這棵二叉樹中,必然存在這兩個數
考慮深度最深的葉子結點cnt[x] = 2 * n - 1, 那麼它的父親結點的cnt[fa] = 6 * n - 11
gcd(2n - 1, 6n - 11) = gcd(2n - 1, -8) = 1 由於2n - 1 是奇數
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define INF 0x3f3f3f3f 5 #define INFLL 0x3f3f3f3f3f3f3f3f 6 #define ll long long 7 #define N 100010 8 9 inline ll GCD(ll a, ll b) 10 { 11 return (ll)b ? GCD(b, a % b) : a; 12 } 13 14 struct Edge 15 { 16 int to, nx; 17 inline Edge() {} 18 inline Edge(int to, int nx) : to(to), nx(nx) {} 19 }edge[N << 1]; 20 21 int head[N], pos; 22 int t, n; 23 ll arr[N]; 24 ll cnt[N]; 25 ll num[N]; 26 ll son[N][2]; 27 int fa[N]; 28 ll sum; 29 30 inline void Init() 31 { 32 memset(head, -1, sizeof head); 33 pos = 0; fa[1] = 1; sum = 0; 34 } 35 36 inline void addedge(int u, int v) 37 { 38 edge[++pos] = Edge(v, head[u]); head[u] = pos; 39 edge[++pos] = Edge(u, head[v]); head[v] = pos; 40 } 41 42 inline void DFS(int u) 43 { 44 cnt[u] = 1; 45 son[u][0] = son[u][1] = 0; 46 for (int it = head[u]; ~it; it = edge[it].nx) 47 { 48 int v = edge[it].to; 49 if (v == fa[u]) continue; 50 fa[v] = u; DFS(v); 51 cnt[u] += cnt[v]; 52 if (son[u][0]) 53 son[u][1] = cnt[v]; 54 else 55 son[u][0] = cnt[v]; 56 } 57 num[u] = (ll)(2 * n - 1) + (ll)(n - cnt[u]) * (cnt[u] - 1) * 2 + (ll)(son[u][0] * son[u][1] * 2); 58 sum += arr[u] * num[u]; 59 } 60 61 inline void work() 62 { 63 if (sum == 0) 64 { 65 puts("0"); 66 return; 67 } 68 int id = 1; 69 for (int i = 1; i <= n; ++i) 70 { 71 if (sum % num[i] == 0) 72 { 73 printf("1\n%d\n", i); 74 return; 75 } 76 if (GCD(num[i], num[fa[i]]) == 1) 77 id = i; 78 } 79 printf("2\n%d %d\n", fa[id], id); 80 } 81 82 inline void Run() 83 { 84 scanf("%d", &t); 85 while (t--) 86 { 87 scanf("%d", &n); 88 Init(); 89 for (int i = 1; i <= n; ++i) scanf("%lld", arr + i); 90 for (int i = 1, u, v; i < n; ++i) 91 { 92 scanf("%d%d", &u, &v); 93 addedge(u, v); 94 } 95 DFS(1); 96 work(); 97 } 98 } 99 100 int main() 101 { 102 #ifdef LOCAL 103 freopen("Test.in", "r", stdin); 104 #endif 105 106 Run(); 107 108 return 0; 109 }
I:lldar Yalalov
題意:n堆石子,每一堆有ai個,兩我的輪流取,取的操做只有兩種
1° 從一堆中取一個
2°每一堆取一個,當且僅當全部堆都至少有一個纔能有這個操做
思路:
若是是奇數堆,那麼取一個和從全部堆中取一個的操做其實是同樣的,由於取的都是奇數個,不會影響勝負 直接% 2 判斷
若是是偶數堆,而且總個數是奇數,那麼先手是必勝的,由於若是最小堆裏面的石子個數是奇數個,那麼只要一直取這裏的,若是他取一排,跟着他取
若是總個數是偶數,而且最小堆裏面石子個數是偶數,那麼是勝利的,由於先手改變命運的次數多一次
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 #define INF 0x3f3f3f3f 5 #define N 110 6 7 int t; 8 int n, sum, Min; 9 int arr[N]; 10 11 inline bool work() 12 { 13 if (n & 1) 14 { 15 return (sum & 1); 16 } 17 if (sum & 1) return true; 18 else 19 { 20 return (Min & 1); 21 } 22 } 23 24 int main() 25 { 26 scanf("%d", &t); 27 while (t--) 28 { 29 scanf("%d", &n); 30 sum = 0, Min = INF; 31 for (int i = 1; i <= n; ++i) scanf("%d", arr + i), sum += arr[i], Min = min(Min, arr[i]); 32 puts(work() ? "Yalalov" : "Shin"); 33 } 34 return 0; 35 }
J:Saeed and Folan
水。
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 5 int t, k; 6 int L[2], R[2], p[2], D[2]; 7 8 int main() 9 { 10 scanf("%d", &t); 11 while (t--) 12 { 13 for (int i = 0; i < 2; ++i) 14 scanf("%d%d%d%d", &L[i], &R[i], &p[i], &D[i]); 15 scanf("%d", &k); 16 for (int i = 0; i < 2; ++i) if (D[i] == 0) 17 D[i] = -1; 18 int ans = 0; 19 if (p[0] == p[1]) ++ans; 20 if (p[0] == L[0]) D[0] = 1; 21 if (p[0] == R[0]) D[0] = -1; 22 if (p[1] == L[1]) D[1] = 1; 23 if (p[1] == R[1]) D[1] = -1; 24 for (int i = 1; i <= k; ++i) 25 { 26 for (int j = 0; j < 2; ++j) 27 p[j] += D[j]; 28 if (p[0] == p[1]) ++ans; 29 for (int j = 0; j < 2; ++j) 30 { 31 if (p[j] == R[j]) D[j] = -1; 32 if (p[j] == L[j]) D[j] = 1; 33 } 34 } 35 printf("%d\n", ans); 36 } 37 return 0; 38 }
K:Another Shortest Path Problem
題意:n個點,n條邊,沒有重邊和自環,每次詢問給出u, v 詢問u -> v的最短路徑
思路:這個圖是一棵樹加一個環,那麼咱們找出這個環中邊權最大的邊
那麼最短路只有兩種情況,通過這條邊和不通過這條邊 而後找LCA處理一下
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 const int DEG = 20; 8 const int maxn = 1e5 + 10; 9 10 struct node{ 11 int u,v; 12 ll w; 13 inline node(){} 14 inline node(int u,int v,ll w): u(u), v(v), w(w){} 15 inline bool operator < (const node &b) 16 { 17 return w < b.w; 18 } 19 }G[maxn]; 20 21 struct Edge{ 22 int to,nxt; 23 ll w; 24 inline Edge(){} 25 inline Edge(int to,int nxt, ll w):to(to), nxt(nxt), w(w) {} 26 }edge[maxn << 1]; 27 28 int n,q; 29 int head[maxn], tot; 30 int father[maxn]; 31 ll dis[maxn]; 32 33 inline int find(int x) 34 { 35 return father[x] == x ? father[x] : father[x] = find(father[x]); 36 } 37 38 inline void mix(int x,int y) 39 { 40 x = find(x); 41 y = find(y); 42 if(x != y) 43 { 44 father[x] = y; 45 } 46 } 47 48 inline bool same(int x,int y) 49 { 50 return find(x) == find(y); 51 } 52 53 inline void addedge(int u,int v,ll w) 54 { 55 edge[tot] = Edge(v, head[u],w); 56 head[u] = tot++; 57 } 58 59 inline void init() 60 { 61 tot = 0; 62 memset(head, -1, sizeof head); 63 for(int i = 1; i <= n; ++i) father[i] = i; 64 } 65 66 int fa[maxn][DEG]; 67 int deg[maxn]; 68 69 inline void BFS(int root) 70 { 71 queue<int>q; 72 deg[root] = 0; 73 fa[root][0] = root; 74 q.push(root); 75 while(!q.empty()) 76 { 77 int tmp = q.front(); 78 q.pop(); 79 for(int i = 1;i < DEG; ++i) 80 { 81 fa[tmp][i] = fa[fa[tmp][i - 1]][i - 1]; 82 } 83 for(int i = head[tmp]; ~i; i = edge[i].nxt) 84 { 85 int v = edge[i].to; 86 if(v == fa[tmp][0]) continue; 87 dis[v] = dis[tmp] + edge[i].w; 88 deg[v] = deg[tmp] + 1; 89 fa[v][0] = tmp; 90 q.push(v); 91 } 92 } 93 } 94 95 inline int LCA(int u, int v) 96 { 97 if(deg[u] > deg[v]) swap(u,v); 98 int hu = deg[u], hv = deg[v]; 99 int tu = u,tv = v; 100 for(int det = hv - hu, i = 0;det; det >>= 1, ++i) 101 { 102 if(det & 1) 103 { 104 tv = fa[tv][i]; 105 } 106 } 107 if(tu == tv) return tu; 108 for(int i = DEG - 1; i >= 0; --i) 109 { 110 if(fa[tu][i] == fa[tv][i]) continue; 111 tu = fa[tu][i]; 112 tv = fa[tv][i]; 113 } 114 return fa[tu][0]; 115 } 116 117 inline ll query(int u,int v) 118 { 119 int root = LCA(u,v); 120 return dis[u] + dis[v] - 2 * dis[root]; 121 } 122 123 int main() 124 { 125 int t; 126 scanf("%d",&t); 127 while(t--) 128 { 129 scanf("%d %d",&n,&q); 130 init(); 131 int a,b; 132 ll cost; 133 for(int i = 1; i <= n; ++i) 134 { 135 scanf("%d %d %lld", &G[i].u, &G[i].v, &G[i].w); 136 } 137 sort(G + 1, G + 1 + n); 138 for(int i = 1; i <= n; ++i) 139 { 140 int u = G[i].u; 141 int v = G[i].v; 142 ll w = G[i].w; 143 if(same(u, v)) 144 { 145 a = u; 146 b = v; 147 cost = w; 148 } 149 else 150 { 151 mix(u,v); 152 addedge(u,v,w); 153 addedge(v,u,w); 154 } 155 } 156 dis[1] = 0; 157 BFS(1); 158 while(q--) 159 { 160 int u,v; 161 scanf("%d %d",&u,&v); 162 ll ans = query(u, v); 163 ans = min(ans, query(u, a) + query(v, b) + cost); 164 ans = min(ans, query(v, a) + query(u, b) + cost); 165 printf("%lld\n",ans); 166 } 167 } 168 return 0; 169 }
L:V--o$\_$o--V
Upsolved.
題意:
$對每個點i求下標小於i的全部點的LCA的點權和$
思路:
考慮一個點對多個點求分別的$LCA$ 能夠樹剖對那些點從當前點到根打標記,那麼目標點對他們求$LCA就是從當前點走到根看一下打的標記最多的是哪一個$
那麼此處也能夠一樣處理,咱們須要設計一種標記,使得從該點到根的路徑上全部標記點加起來剛好是當前點權值
咱們能夠這麼處理 在這裏約定$w[u] 表示點u的點權,x[u] 表示樹上的標記, fa[u] 表示點u的父親$
那麼 $x[u] = w[fa[u]] - w[i]$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define ll long long 5 #define N 200010 6 int t, n, w[N]; 7 vector <int> G[N]; 8 9 ll dis[N]; 10 int deep[N], fa[N], sze[N], son[N], top[N], p[N], fp[N], cnt; 11 void DFS(int u) 12 { 13 sze[u] = 1; 14 for (auto v : G[u]) 15 { 16 deep[v] = deep[u] + 1; 17 dis[v] = w[v] - w[u]; 18 DFS(v); sze[u] += sze[v]; 19 if (!son[u] || sze[v] > sze[son[u]]) son[u] = v; 20 } 21 } 22 23 void getpos(int u, int sp) 24 { 25 top[u] = sp; 26 p[u] = ++cnt; 27 fp[cnt] = u; 28 if (!son[u]) return; 29 getpos(son[u], sp); 30 for (auto v : G[u]) if (v != son[u]) 31 getpos(v, v); 32 } 33 34 namespace SEG 35 { 36 ll sum[N << 2], add[N << 2], lazy[N << 2]; 37 void build(int id, int l, int r) 38 { 39 sum[id] = lazy[id] = 0; 40 if (l == 1) sum[id] = dis[1]; 41 if (l == r) 42 { 43 add[id] = dis[fp[l]]; 44 return; 45 } 46 int mid = (l + r) >> 1; 47 build(id << 1, l, mid); 48 build(id << 1 | 1, mid + 1, r); 49 add[id] = add[id << 1] + add[id << 1 | 1]; 50 } 51 void work(int id, int l, int r, int ql, int qr, ll &res) 52 { 53 if (l >= ql && r <= qr) 54 { 55 res += sum[id]; 56 sum[id] += add[id]; 57 ++lazy[id]; 58 return; 59 } 60 if (lazy[id]) 61 { 62 lazy[id << 1] += lazy[id]; 63 sum[id << 1] += lazy[id] * add[id << 1]; 64 lazy[id << 1 | 1] += lazy[id]; 65 sum[id << 1 | 1] += lazy[id] * add[id << 1 | 1]; 66 lazy[id] = 0; 67 } 68 int mid = (l + r) >> 1; 69 if (ql <= mid) work(id << 1, l, mid, ql, qr, res); 70 if (qr > mid) work(id << 1 | 1, mid + 1, r, ql, qr, res); 71 sum[id] = sum[id << 1] + sum[id << 1 | 1]; 72 } 73 } 74 75 ll work(int u, int v) 76 { 77 ll res = 0; 78 while (top[u] != top[v]) 79 { 80 if (deep[top[u]] < deep[top[v]]) swap(u, v); 81 SEG::work(1, 1, n, p[top[u]], p[u], res); 82 u = fa[top[u]]; 83 } 84 if (deep[u] > deep[v]) swap(u, v); 85 SEG::work(1, 1, n, p[u], p[v], res); 86 return res; 87 } 88 89 void init() 90 { 91 for (int i = 1; i <= n; ++i) G[i].clear(), son[i] = 0; 92 cnt = 0; 93 } 94 95 int main() 96 { 97 scanf("%d", &t); 98 while (t--) 99 { 100 scanf("%d", &n); init(); 101 for (int i = 1; i <= n; ++i) scanf("%d", w + i); 102 for (int i = 1; i <= n; ++i) 103 { 104 scanf("%d", fa + i); 105 G[fa[i]].push_back(i); 106 } dis[1] = w[1]; DFS(1); getpos(1, 1); 107 SEG::build(1, 1, n); 108 for (int i = 2; i <= n; ++i) printf("%lld%c", work(1, i), " \n"[i == n]); 109 } 110 return 0; 111 }