自己口胡的写法()
为啥会有零零星星的错误啊,完全不知道怎么回事
抓狂·
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
using namespace std;
const int maxn = 1e4 + 5;
const int maxm = 2e4 + 5;
namespace G {
//原图
struct edge { int to, w, nxt; } e[maxm<<1];
int tot = 1, head[maxn];
inline void add(int u, int v, int w) {
e[++tot].to = v;
e[tot].w = w;
e[tot].nxt = head[u];
head[u] = tot;
}
}
namespace g {
//圆方树
struct edge { int to, w, nxt; } e[maxn<<1];
int tot = 1, head[maxn<<1];
inline void add(int u, int v, int w) {
e[++tot].to = v;
e[tot].w = w;
e[tot].nxt = head[u];
head[u] = tot;
}
}
int n, m, q, dfncnt, cnt, top;
int dfn[maxn], low[maxn], stk[maxn];
int ring[maxn], val[maxn];
int dis[maxn<<1], dep[maxn<<1], st[14][maxn<<1];
bool vis[maxn];
vector<int> pv[maxn];
inline void build(int u, int last) {
//建圆方树
using namespace G;
dfn[u] = low[u] = ++dfncnt;
stk[++top] = u;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(i == last) continue;
if(!dfn[v]) {
build(v, i^1);
low[u] = min(low[u], low[v]);
if(low[v] >= dfn[u]) {
//把这个点双的点都存进vector里
pv[++cnt].push_back(u);
int x;
while((x = stk[top--])) {
pv[cnt].push_back(x);
if(x == v) break;
}
}
}
else low[u] = min(low[u], dfn[v]);
}
}
inline void bfs(int id) {
//bfs求出第 id 个环上,每个点距离最前面那个点的距离
//vis[u] 表示 u 是否在当前的点双上
//ring[id] 代表整个环的长度
using namespace G;
queue<int> q;
q.push(pv[id][0]);
dis[pv[id][0]] = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
vis[u] = false;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
if(!vis[v]) continue;
ring[id] += e[i].w;
val[v] = dis[v] = dis[u] + e[i].w;
q.push(v);
}
}
}
inline void dfs(int u, int fa) {
//dfs预处理 lca,还有每个点到根节点的距离
using namespace g;
st[0][u] = fa;
dep[u] = dep[fa] + 1;
for(int i = 1; (1<<i)+1 <= dep[u]; i++)
st[i][u] = st[i-1][st[i-1][u]];
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
dis[v] = dis[u] + e[i].w;
dfs(v, u);
}
}
inline int lca(int& x, int& y) {
//求lca的同时,也能求出距离 x, y 最近的 lca的儿子
if(dep[x] < dep[y]) swap(x, y);
for(int i = 13; i >= 0; i--)
if(dep[y]+(1<<i) <= dep[x]) x = st[i][x];
if(x == y) return x;
for(int i = 13; i >= 0; i--)
if((1<<i)<dep[x] && st[i][x] != st[i][y])
x = st[i][x], y = st[i][y];
return st[0][x];
}
int main() {
freopen("P5236_1.in", "r", stdin);
freopen("test.out", "w", stdout);
scanf("%d %d %d", &n, &m, &q);
//原图加边
for(int i = 1, u, v, w; i <= m; i++) {
using namespace G;
scanf("%d %d %d", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
build(1, 0);
for(int i = 1; i <= cnt; i++) {
//把每个点双都处理一下
using namespace g;
for(int x : pv[i]) vis[x] = true;
bfs(i);
//只有两个点,说明只是一条割边,直接连接即可
if(pv[i].size() == 2) add(pv[i][0], pv[i][1], ring[i]);
else {
add(pv[i][0], i+n, 0);
for(int x : pv[i]) if(x != pv[i][0]) add(i+n, x, min(dis[x], ring[i]-dis[x]));
}
}
dfs(1, 0);
for(int i = 1, x, y; i <= q; i++) {
scanf("%d %d", &x, &y);
int ans = dis[x] + dis[y], zx = lca(x, y);
if(zx <= n) printf("%d\n", ans - (dis[zx]<<1));
//lca 是圆点,直接求
else {
int tmp = min(abs(val[x]-val[y]), ring[zx-n] - abs(val[x]-val[y]));
printf("%d\n", ans + tmp - (dis[x]+dis[y]));
//否则就求距离x, y 最近的,lca的两个儿子之间的最短距离
}
}
return 0;
}