时限:1s 内存:64MB
题目描述
Bob发现字节大地上有个城市形成了一个树形结构。作为一个旅游爱好者,Bob想要在个城市之间穿梭。经过调查,Bob知道了每条路的花费。由于时间对他来说很宝贵,他希望字节大地的国王能够修建一条新路来节省时间。现在Bob有个旅行计划,每个旅行计划的起点和终点也都知道,Bob希望你能帮助他计算,通过新建一条道路,他能节省多少时间。Bob总是会选择最短路线进行旅行。如果新建一条道路不能节省时间,那么答案为。
输入格式
输入文件的第一行包含两个整数和,分别表示城市个数和旅行计划的个数。接下来行,每行包含三个整数和,表示Bob需要花费单位时间通过城市和之间的道路。前条路表示原来的树形结构,最后一条路表示新修的道路。接下来行询问,每行包含两个整数和,表示Bob计划从旅行到。
输出格式
对于每个询问,输出一行表示表示该询问的答案。
样例输入
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
样例输出
0
2
0
2
2
分析:
- 注意都是正权边。
- 本来是一棵树的,可以用树形dp搞出每个点到根的路径费用,求出lca,转而求出两点之间的费用。
- 后来加了一条边,形成了一棵基环树。
- 找到那个环,对环上的每个点所领导的子树染色,并处理出此时每个点到它所属的根(这些根就是环上的点)的费用。
- 对于询问的两个点,如果是同一种颜色,就是0(新添加的边对它没有作用);如果不是同一种颜色,u到其根的费用+v到其根的费用+u的根到v的根的费用(这个可以用min(原始树上两点的费用,环上的费用和-原始树上两点的费用)求出)。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100000
#define MAXLOG 20
struct node{
int v,w;
node *next;
}edge[MAXN*2+10],*adj[MAXN+10],*ecnt=&edge[0];
int n,Q,P[MAXN+10][MAXLOG+10],dep[MAXN+10],fa[MAXN+10],Logn,sum;
int b[MAXN+10],c[MAXN+10];
int col[MAXN+10],pnt[MAXN+10],cntp;
bool vis[MAXN+10],tag[MAXN+10],cir[MAXN+10];
void addedge(int u,int v,int w)
{
node *p=++ecnt;
p->v=v,p->w=w;
p->next=adj[u];
adj[u]=p;
}
void dfs1(int u)
{
vis[u]=true;
for(node *p=adj[u];p;p=p->next){
if(vis[p->v])
continue;
fa[p->v]=u,dep[p->v]=dep[u]+1;
b[p->v]=b[u]+p->w;
dfs1(p->v);
}
}
void LCA_pre()
{
memset(P,-1,sizeof P);
for(int i=1;i<=n;i++)
P[i][0]=fa[i];
for(Logn=0;(1<<Logn)<=n;Logn++);
Logn--;
for(int j=1;j<=Logn;j++)
for(int i=1;i<=n;i++)
if(P[i][j-1]!=-1)
P[i][j]=P[P[i][j-1]][j-1];
}
int LCA(int x,int y)
{
if(dep[x]>dep[y])
swap(x,y);
int Logy;
for(Logy=0;(1<<Logy)<=dep[y];Logy++);
Logy--;
for(int i=Logy;i>=0;i--)
if(dep[P[y][i]]>=dep[x])
y=P[y][i];
if(x==y) return x;
for(int i=Logy;i>=0;i--)
if(P[x][i]!=-1&&P[y][i]!=-1&&P[x][i]!=P[y][i])
x=P[x][i],y=P[y][i];
return P[x][0];
}
void dfs2(int u,int mark)
{
vis[u]=true,col[u]=mark;
for(node *p=adj[u];p;p=p->next){
if(cir[p->v]||vis[p->v]) continue;
c[p->v]=c[u]+p->w;
dfs2(p->v,mark);
}
}
void Circle()
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
int lca=LCA(x,y);
sum=b[x]+b[y]-2*b[lca]+w;
for(int u=x;u!=lca;u=fa[u])
cir[u]=true,pnt[++cntp]=u;
for(int u=y;u!=lca;u=fa[u])
cir[u]=true,pnt[++cntp]=u;
cir[lca]=true,pnt[++cntp]=lca;
addedge(x,y,w);
addedge(y,x,w);
memset(vis,0,sizeof vis);
for(int i=1;i<=cntp;i++){
c[pnt[i]]=0;
dfs2(pnt[i],pnt[i]);
}
}
void read()
{
int x,y,w;
scanf("%d%d",&n,&Q);
for(int i=1;i<n;i++){
scanf("%d%d%d",&x,&y,&w);
addedge(x,y,w);
addedge(y,x,w);
}
fa[1]=0,dep[1]=1,b[1]=0;
memset(vis,0,sizeof vis);
dfs1(1);
LCA_pre();
Circle();
}
int dist(int x,int y)
{
int lca=LCA(x,y);
return min(b[x]+b[y]-2*b[lca],sum-b[x]-b[y]+2*b[lca]);
}
int main()
{
int x,y;
read();
while(Q--){
scanf("%d%d",&x,&y);
int d=c[x]+c[y]+dist(col[x],col[y]);
int lca=LCA(x,y);
if(col[x]==col[y]){
printf("0\n");
continue;
}
if(d<b[x]+b[y]-2*b[lca])
printf("%d\n",b[x]+b[y]-2*b[lca]-d);
else
printf("0\n");
}
}