发展城市

Time Limit: 20 Sec Memory Limit: 512 MB

Description

众所周知,Hzwer学长是一名高富帅,他打算投入巨资发展一些小城市。
  Hzwer打算在城市中开N个宾馆,由于Hzwer非常壕,所以宾馆必须建在空中,但是这样就必须建立宾馆之间的连接通道。机智的Hzwer在宾馆中修建了N-1条隧道,也就是说,宾馆和隧道形成了一个树形结构。
  Hzwer有时候会花一天时间去视察某个城市,当来到一个城市之后,Hzwer会分析这些宾馆的顾客情况。对于每个顾客,Hzwer用三个数值描述他:(S, T, V)表示该顾客这天想要从宾馆S走到宾馆T,他的速度是V。
  Hzwer需要做一些收集一些数据,这样他就可以规划他接下来的投资。
  其中有一项数据就是收集所有顾客可能的碰面次数。
  每天清晨,顾客同时从S出发以V的速度前往T(注意S可能等于T),当到达了宾馆T的时候,顾客显然要找个房间住下,那么别的顾客再经过这里就不会碰面了。特别的,两个顾客同时到达一个宾馆是可以碰面的。同样,两个顾客同时从某宾馆出发也会碰面。

Input

第一行一个正整数T(1<=T<=20),表示Hzwer发展了T个城市,并且在这T个城市分别视察一次。
 对于每个T,第一行有一个正整数N(1<=N<=10^5)表示Hzwer在这个城市开了N个宾馆。
 接下来N-1行,每行三个整数X,Y,Z表示宾馆X和宾馆Y之间有一条长度为Z的隧道
 再接下来一行M表示这天顾客的数量。
 紧跟着M行每行三个整数(S, T, V)表示该顾客会从宾馆S走到宾馆T,速度为v

Output

对于每个T,输出一行,表示顾客的碰面次数。

Sample Input

2
  3
  1 2 1
  2 3 1
  3
  1 3 2
  3 1 1
  1 2 3
  1
  0

Sample Output

2
  0

HINT

1<=T<=20 1<=N<=10^5 0<=M<=10^3 1<=V<=10^6 1<=Z<=10^3

Main idea

给定若干个顾客,每个顾客会匀速从一个点走到另外一个点,问有几对人会在路上相遇。

Solution

由于人数较少,所以我们可以O(m^2)判断两人是否相交。

首先,两个人相遇只可能是在路径重叠的部分相遇,所以我们先对两人的路径求交,这里提供一种对树上路径求交的方法:

求出AB两人路径的交:
      设A路径为a.u->a.v,B路径为b.u->b.v。那么我们求出 LCA(a.u,b.u),LCA(a.v,b.v),LCA(a.u,b.v),LCA(b.u,a.v),然后保留下在AB路径上的点。(判断一个点是否在路径上:若u在LCA(x,y)的子树中,且u为LCA(u,x)或者LCA(u,y),则u在路径x,y上),然后按照dfs序位置排序,去重,保留下后两个点,则后两个点即是路径的端点。

但是这样求交的话需要多次查询LCA,我们用每次log的时间查询显然会超时,于是我们引进O(nlog(n))预处理,O(1)查询的LCA。

O(1)查询的LCA:
      我们先求出对于这棵树的欧拉序(欧拉序:记下每个点第一次访问的位置以及回溯完的位置),然后我们用那么这时候x,y之间的LCA也就是 [pos[x],pos[y]] 区间内深度最小的点(pos[x]表示点x第一次在欧拉序中出现的位置),这个区间最小值用RMQ求即可。

现在我们已经求出了路径的交集,然后我们暴力分类讨论一下。如果没有交集则必然不相交,若交于一点判断一下到达时间即可,否则:

先考虑两人运动的方向。我们记录p.u,p.v表示路径交集的两个端点。A1表示A到先进入路径的端点,A2表示A后到的端点,B1、B2类似(用距离长短判断即可),如果A1=B1则表示两人同向运动,否则表示相向运动。然后我们讨论一下:

**同向运动:**如果两人同向运动,那么若先进入路径的后离开路径,则两人会相遇。
    **相向运动:**如果两人相向运动,则我们记录到端点的时间,如果两个人在路径上的时间有交集的话,则会相遇。

然后这样判断一下就可以求出答案了,但是由于double定义下的除法速度很慢,会被卡常数,所以我们再用在long long定义下的交叉相乘来判断以上情况。这样我们就解决了这道题(≧▽≦)/

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#include<bits/stdc++.h>
using namespace std;
typedef long long s64;

const int ONE = 100005;

int T;
int n,m;
int x,y,z;
int next[ONE*2],first[ONE],go[ONE*2],w[ONE*2],tot;
int pos[ONE],dfn_cnt,Dep[ONE],size[ONE];
int MinD[ONE*2][18],NumD[ONE*2][18];
int Log[ONE*2],Bin[18];
int Stk[5],top,fc;
int Ans;
s64 d[ONE];

struct power
{
int u,v;
int val;
}a[1005],p;

namespace input
{
const int BufferSize = 1 << 16 | 1;

char buffer[BufferSize];
char *head = buffer + BufferSize;
const char *tail = head;

inline char nextChar()
{
if (head == tail)
{
fread(buffer, 1, BufferSize, stdin);
head = buffer;
}
return *head++;
}

inline int get()
{
static char c;
while ((c = nextChar()) < '0' || c > '9');

int res = c - '0';
while ((c = nextChar()) >= '0' && c <= '9')
res = res * 10 + c - '0';
return res;
}
}
using input::get;

inline void Add(int u,int v,int z)
{
next[++tot]=first[u]; first[u]=tot; go[tot]=v; w[tot]=z;
next[++tot]=first[v]; first[v]=tot; go[tot]=u; w[tot]=z;
}

namespace F
{
int Dfs(int u,int father)
{
pos[u] = ++dfn_cnt;
Dep[u] = Dep[father] + 1;
size[u] = 1;
MinD[dfn_cnt][0]=Dep[u]; NumD[dfn_cnt][0]=u;
for(int e=first[u];e;e=next[e])
{
int v=go[e];
if(v==father) continue;
d[v] = d[u] + w[e];
Dep[v] = Dep[u] + 1;
Dfs(v,u);
size[u] += size[v];
MinD[++dfn_cnt][0]=Dep[u]; NumD[dfn_cnt][0]=u;
}
}

inline void Pre_Rmq()
{
for(int j=1;j<=17;j++)
for(int i=1;i<=dfn_cnt;i++)
if(i+Bin[j]-1 <= dfn_cnt)
{
int Next = i + Bin[j-1];
if(MinD[i][j-1] < MinD[Next][j-1])
MinD[i][j]=MinD[i][j-1], NumD[i][j]=NumD[i][j-1];
else
MinD[i][j]=MinD[Next][j-1], NumD[i][j]=NumD[Next][j-1];
}
else break;
}
}

inline int LCA(int x,int y)
{
x=pos[x]; y=pos[y];
if(x > y) swap(x,y);
int T = Log[y - x +1];
if(MinD[x][T] < MinD[y-Bin[T]+1][T]) return NumD[x][T];
return NumD[y-Bin[T]+1][T];
}

inline s64 dist(int x,int y)
{
return d[x] + d[y] - (d[LCA(x,y)] << 1) ;
}

namespace PD
{
inline bool inroad(int u,power a)
{
int lca = LCA(a.u,a.v);
if(LCA(u,lca) != lca) return 0;
return (LCA(u,a.u)==u || LCA(u,a.v)==u);
}
}

inline void Sort(int n)
{
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
if(pos[Stk[i]] > pos[Stk[j]])
swap(Stk[i], Stk[j]);
}

inline power Get_road(power a,power b)
{
fc=top=0;
Stk[++fc] = LCA(a.u,b.u); Stk[++fc] = LCA(a.v,b.v);
Stk[++fc] = LCA(a.u,b.v); Stk[++fc] = LCA(b.u,a.v);
for(int i=1;i<=fc;i++)
if(PD::inroad(Stk[i],a) && PD::inroad(Stk[i],b))
Stk[++top] = Stk[i];

Sort(top);
top=unique(Stk+1,Stk+top+1) - Stk - 1;

power p; p.val = 0;
if(top==0) p.u = p.v = 0;
if(top==1) p.u = p.v = Stk[1];
if(top==2) p.u=Stk[1], p.v=Stk[2];
if(top==3) p.u=Stk[2], p.v=Stk[3];
return p;
}

inline bool pmin(s64 a,s64 b,s64 c)
{
if(a<=b && b<=c) return 1;
return 0;
}

inline int Deal(int x,int y)
{
if(a[x].u == a[y].u) return 1;
p = Get_road(a[x],a[y]);
if(p.u==p.v)
{
if(!p.u) return 0;
return (s64) dist(a[x].u,p.u) * a[y].val == (s64) dist(a[y].u,p.u) * a[x].val;
}

int A1,A2,B1,B2;
double A1_time,A2_time,B1_time,B2_time;
if(dist(a[x].u,p.u) < dist(a[x].u,p.v)) A1=p.u, A2=p.v;else A1=p.v, A2=p.u;
if(dist(a[y].u,p.u) < dist(a[y].u,p.v)) B1=p.u, B2=p.v;else B1=p.v, B2=p.u;

A1_time=(s64)dist(A1,a[x].u)*a[y].val; A2_time=(s64)dist(A2,a[x].u)*a[y].val;
B1_time=(s64)dist(B1,a[y].u)*a[x].val; B2_time=(s64)dist(B2,a[y].u)*a[x].val;

if(A1==B1)//same
{
if(A1_time == B1_time) return 1;
if(A1_time < B1_time) return A2_time >= B2_time;
return A2_time <= B2_time;
}
else
{
if(pmin(A1_time,B1_time,A2_time)) return 1;
if(pmin(A1_time,B2_time,A2_time)) return 1;
if(pmin(B1_time,A1_time,B2_time)) return 1;
if(pmin(B1_time,A2_time,B2_time)) return 1;
return 0;
}
}

inline void Solve()
{
n=get();
dfn_cnt=tot=0;
memset(first,0,sizeof(first));
for(int i=1;i<n;i++)
{
x=get(); y=get(); z=get();
Add(x,y,z);
}

F::Dfs(1,0); F::Pre_Rmq();

m=get();
for(int i=1;i<=m;i++)
{
a[i].u=get(); a[i].v=get(); a[i].val=get();
}

Ans = 0;

for(int i=1;i<=m;i++)
for(int j=i+1;j<=m;j++)
{
Ans += Deal(i,j);
}

printf("%d\n",Ans);
}

int main()
{
Log[0]=-1; for(int i=1;i<=2e5;i++) Log[i] = Log[i>>1] + 1;
Bin[0]=1; for(int i=1;i<=17; i++) Bin[i] = Bin[i-1] << 1;

T=get();

while(T--)
Solve();
}