思路:
第一次做多颗树合用一个lca,记录一下,其实就是一开始init,在加边的时候做一下并查集,把一棵树上的点都算到一个集合去,然后遍历1到n,如果fa[i] == i的话就搞一下lca,这里多颗树是共用一个欧拉序的,但不影响此模板的正确性,因为记录的第一次数显示的位置的都是正确的。
初始化 -> lca+st表 -> 在线询问。
数据有点水把,最极限情况1e10应该要开long long的,int也能过,就这样。
#include <bits/stdc++.h>
#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())
using namespace std;
typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;
template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }
const int maxn = 2*(int)10000+100; //要开两倍点数量的大小(欧拉序长度)
int n, q, m, fa[maxn];
struct LCA
{
#define type long long
struct node{int to;type w;node(){}node(int _to,type _w):to(_to),w(_w){}};
type dist[maxn];
int path[maxn],dep[maxn],loc[maxn],len[maxn],LOG[maxn],all,n;
int dp[25][maxn], point[25][maxn]; //2^20 == 1e6 2^25 == 3e7
vector<node> G[maxn];
void dfs(int u, int now) {
path[++all] = u;
loc[u] = all;
dep[all] = now;
for (node cur : G[u]) {
int v = cur.to;
if (loc[v]) continue;
len[v] = now+1;
dist[v] = dist[u]+cur.w;
dfs(v, now+1);
path[++all] = u;
dep[all] = now;
}
}
void initRMQ(int n)
{
LOG[0] = -1;
for (int i = 1; i <= all; ++i) {
dp[0][i] = dep[i];
point[0][i] = path[i];
LOG[i] = ((i&(i-1)) == 0 ? LOG[i-1]+1 : LOG[i-1]);
}
for (int i = 1; (1<<i) <= all; ++i) {
for (int j = 1; j+(1<<i)-1 <= all; ++j) {
if (dp[i-1][j] < dp[i-1][j+(1<<(i-1))]) {
dp[i][j] = dp[i-1][j];
point[i][j] = point[i-1][j];
} else {
dp[i][j] = dp[i-1][j+(1<<(i-1))];
point[i][j] = point[i-1][j+(1<<(i-1))];
}
}
}
}
int queryLCA(int l,int r)
{
l = loc[l]; r = loc[r];
if(l>r) swap(l,r);
int k = LOG[r-l+1];
/*
貌似下面这种写法更快
记得把上面预处理的LOG删了
P 3379
int k=0;
while((1<<k)<=r-l+1) k++;
k--;
*/
if(dp[k][l] < dp[k][r-(1<<k)+1]) return point[k][l];
else return point[k][r-(1<<k)+1];
}
type getDist(int a,int b){
return dist[a]+dist[b]-2*dist[queryLCA(a,b)];
}
int getLen(int a,int b){return len[a]+len[b]-2*len[queryLCA(a,b)];}
void init(int _n)
{
n = _n;
all = 0;
for(int i = 0;i <= n; i++)
{
loc[i] = 0;
dist[i] = 0;
len[i] = 0;
G[i].clear();
}
}
void addEdge(int a,int b,type w=1)
{
G[a].eb(node(b,w));
G[b].eb(node(a,w));
}
void solve(int root)
{
dfs(root, 1);
initRMQ(all);
}
#undef type
}lca;
int findRoot(int x) {
if (x == fa[x]) return x;
else {
return (fa[x] = findRoot(fa[x]));
}
}
void uniRoot(int a, int b) {
int aa = findRoot(a);
int bb = findRoot(b);
if (aa != bb) fa[bb] = aa;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.precision(10);
cout << fixed;
#ifdef LOCAL_DEFINE
freopen("input.txt", "r", stdin);
#endif
while (cin >> n >> m >> q) {
for (int i = 1; i <= n; ++i) fa[i] = i;
lca.init(n);
forn(i, m) {
int u, v, val;
cin >> u >> v >> val;
lca.addEdge(u, v, val);
lca.addEdge(v, u, val);
uniRoot(u, v);
}
for1(i, n) if (fa[i] == i) lca.solve(i);
while (q--) {
int a, b;
cin >> a >> b;
if (findRoot(a) != findRoot(b))
cout << "Not connected" << '\n';
else {
cout << lca.getDist(a, b) << '\n';
}
}
}
#ifdef LOCAL_DEFINE
cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
return 0;
}