/*
由于输入图是一个树,所以可以任意指定一个节点为root结点,然后用LCATarjan算法离线计算任意被查询两个点的LCA,则:
dist(i, j) = dist(root, i) + dist(root, j) - 2 * dist(root, lca(i, j))
寻找LCA的Tarjan算法,LCATarjan算法是一个离线算法,即所有查找请求是一次性同时处理的,而不是输入
一个处理一个.Tarjan算法主要用到了并查集和DFS,利用并查集来在DFS往上返回的时候改变结点自身的LCA.
LCATarjan的主要框架是:
lcaTarjan(int curnodeid, int curdist) //curdist表示root到curnodeid的距离
{
dist(root, curnodeid) = curdist;
lca(curnodeid) = curnodeid; //第一次访问到某个节点就将其lca置为自身
for(all request related to curnodeid) //遍历所有与curnodeid有关的查询请求
{
int toid = get opposite point; //得到查询的另一个端点
if(request has not been processed && toid has been visited)
{
int lca = find(toid); //利用并查集寻找toid与curnodid当前lca;
dist(curnodeid, toid) = dist(root, curnodid) + dist(root, toid) - 2 * dist(root, lca(curnodeid, roid));
}
}
for(all curnodid's sons sid)
{
if(!v[sid]) lcaTarjan(sid, curdist + edgeweight(curnodid, sid));
lca(sid) = curnodid; //dfs返回时置sid的lca为父亲curnodid;
}
}
*/
#include <iostream>
#include <vector>
#define MAX_N 40005
#define MAX_Q 10005
using namespace std;
struct edge
{
int to, dist;
edge *nexte;
edge()
{
nexte = NULL;
}
};
struct querry
{
int from, to, dist;
bool v;
}querrys[MAX_Q + 1];
struct node
{
int sid, dist;
bool v;
edge *nexte;
vector<querry*> q;
}nodes[MAX_N + 1];
int fn, rn, qn;
void insertEdge(int from, int to, int dist)
{
edge *newedge = new edge();
newedge->to = to; newedge->dist = dist;
if(!nodes[from].nexte) nodes[from].nexte = newedge;
else{
edge *curedge = nodes[from].nexte;
while(curedge->nexte)
curedge = curedge->nexte;
curedge->nexte = newedge;
}
}
int find(int nid)
{
if(nid == nodes[nid].sid) return nid;
else return nodes[nid].sid = find(nodes[nid].sid);
}
void lcaTarjan(int curid, int curdist)
{
nodes[curid].dist = curdist;
nodes[curid].sid = curid;
vector<querry*>::iterator iter = nodes[curid].q.begin();
for(; iter != nodes[curid].q.end(); iter++)
{
int toid = (*iter)->from + (*iter)->to - curid;
if((*iter)->v || !nodes[toid].v) continue;
int lca = find(toid);
(*iter)->dist = nodes[curid].dist + nodes[toid].dist - 2 * nodes[lca].dist;
(*iter)->v = true;
}
edge *curedge = nodes[curid].nexte;
while(curedge)
{
if(!nodes[curedge->to].v)
{
nodes[curedge->to].v = true;
lcaTarjan(curedge->to, curdist + curedge->dist);
nodes[curedge->to].sid = curid;
}
curedge = curedge->nexte;
}
}
int main()
{
int i, from, to, dist;
char dir;
scanf("%d%d", &fn, &rn);
for(i = 0; i < rn; i++)
{
scanf("%d%d%d", &from, &to, &dist);
getchar();
scanf("%c", &dir);
insertEdge(from, to, dist);
insertEdge(to, from, dist);
}
scanf("%d", &qn);
for(i = 0; i < qn; i++)
{
scanf("%d%d", &from, &to);
querrys[i].from = from; querrys[i].to = to;
nodes[from].q.push_back(&querrys[i]);
nodes[to].q.push_back(&querrys[i]);
}
nodes[1].v = true;
lcaTarjan(1, 0);
for(i = 0; i < qn; i++)
printf("%d/n", querrys[i].dist);
return 0;
}
POJ 1986 Distance Queries
最新推荐文章于 2023-01-25 21:11:40 发布