Bob has traveled to byteland, he find the
N
cities in byteland formed a tree structure, a tree structure
is very special structure, there is exactly one path connecting each pair of nodes, and a tree with
N
nodes has
N−1
edges.
As a traveler, Bob wants to journey between those
N
cities, and he know the time each road will cost.
he advises the king of byteland building a new road to save time, and then, a new road was built. Now Bob
has
Q
journey plan, give you the start city and destination city, please tell Bob how many time is saved
by add a road if he always choose the shortest path. Note that if it's better not journey from the new roads,
the answer is
0
.
First line of the input is a single integer T ( 1≤T≤20 ), indicating there are T test cases.
For each test case, the first will line contain two integers
N
(
2≤N≤105
) and
Q
(
1≤Q≤105
), indicating
the number of cities in byteland and the journey plans. Then
N
line followed, each line will contain three
integer
x
,
y
(
1≤x,y≤N
) and
z
(
1≤z≤1000
) indicating there is a road cost
z
time connect
the
xth
city and the
yth
city, the first
N−1
roads will form a tree structure, indicating the original roads,
and the
Nth
line is the road built after Bob advised the king. Then
Q
line followed, each line will contain two
integer
x
and
y
(
1≤x,y≤N
), indicating there is a journey plan from the
xth
city to
yth
city.
For each case, you should first output Case #t:
in a single line, where
t
indicating the case number between
1
and
T
,
then
Q
lines followed, the
ith
line contains one integer indicating the time could saved in
ith
journey plan.
1 5 5 1 2 3 2 3 4 4 1 5 3 5 1 3 1 5 1 2 1 3 2 5 3 4 4 5
Case #1: 0 2 0 22
题意:在原有图的基础上加一条边。问加边之后是不是减少了距离,如果减少了就输出减少了多少。
如果没减少就输出0.
LCA水题
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; //#pragma comment(linker, "/STACK:102400000,102400000") //不需要申请系统栈 const int N = 1e5+100; const int M = 35; int dp[2*N][M]; //这个数组记得开到2*N,因为遍历后序列长度为2*n-1 bool vis[N]; struct edge { int u,v,w,next; }e[2*N]; int tot,head[N]; inline void add(int u ,int v ,int w ,int &k) { e[k].u = u; e[k].v = v; e[k].w = w; e[k].next = head[u]; head[u] = k++; u = u^v; v = u^v; u = u^v; e[k].u = u; e[k].v = v; e[k].w = w; e[k].next = head[u]; head[u] = k++; } int ver[2*N],R[2*N],first[N],dir[N]; //ver:节点编号 R:深度 first:点编号位置 dir:距离 void dfs(int u ,int dep) { vis[u] = true; ver[++tot] = u; first[u] = tot; R[tot] = dep; for(int k=head[u]; k!=-1; k=e[k].next) if( !vis[e[k].v] ) { int v = e[k].v , w = e[k].w; dir[v] = dir[u] + w; dfs(v,dep+1); ver[++tot] = u; R[tot] = dep; } } void ST(int n) { for(int i=1;i<=n;i++) dp[i][0] = i; for(int j=1;(1<<j)<=n;j++) { for(int i=1;i+(1<<j)-1<=n;i++) { int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1]; dp[i][j] = R[a]<R[b]?a:b; } } } //中间部分是交叉的。 int RMQ(int l,int r) { int k=0; while((1<<(k+1))<=r-l+1) k++; int a = dp[l][k], b = dp[r-(1<<k)+1][k]; //保存的是编号 return R[a]<R[b]?a:b; } int LCA(int u ,int v) { int x = first[u] , y = first[v]; if(x > y) swap(x,y); int res = RMQ(x,y); int cnt=ver[res]; return dir[u]+dir[v]-2*dir[cnt]; } int main() { //freopen("Input.txt","r",stdin); //freopen("Out.txt","w",stdout); int t; scanf("%d",&t); for(int cas=1;cas<=t;cas++) { int n,q,num = 0; scanf("%d%d",&n,&q); memset(head,-1,sizeof(head)); memset(vis,false,sizeof(vis)); for(int i=1; i<n; i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); add(u,v,w,num); } int a,b,c; scanf("%d%d%d",&a,&b,&c); printf("Case #%d:\n",cas); tot = 0; dir[1] = 0; dfs(1,1); ST(2*n-1); while(q--) { int u,v; scanf("%d%d",&u,&v); int lca = LCA(u,v);//u v 之间的距离 // cout<<lca<<"----------"<<endl; int lca1=min(LCA(u,a)+LCA(v,b),LCA(u,b)+LCA(v,a))+c; lca-=lca1; //cout<<lca1<<"*********"<<endl; if(lca<0) lca=0; printf("%d\n",lca); } } }