# [Luogu 1967] NOIP2013 货车运输

<题目链接>

Capella：好，好…

LCA 考虑倍增算法（树剖不想写了），使用两个 Sparse Table（通称 ST 表），一个存树上路径，一个存树上限重最小值。

#include <algorithm>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstring>

const int MAXN=100010, MAXM=500010;

int n, m, q;

struct Edge
{
int u, v, w;
void Read(void)
{
scanf("%d %d %d", &u, &v, &w);
}
bool operator <(const Edge &rhs) const
{
return w>rhs.w;
}
}s[MAXM];

struct Graph
{
int *depth;
struct Edge
{
int to, w;
Edge *next;
Edge(int to, int w, Edge* next): to(to), w(w), next(next){}
~Edge(void)
{
if(next!=nullptr)
delete next;
}
}**head;
Graph(int n): depth(new int[n+1]), head(new Edge*[n+1])
{
memset(depth, 0, (n<<2)+4);
for(int i=1; i<=n; ++i)
head[i]=nullptr;
}
~Graph(void)
{
delete[] depth;
for(int i=1; i<=n; ++i)
delete head[i];
delete[] head;
}
void AddEdges(int u, int v, int w)
{
head[u]=new Edge(v, w, head[u]);
head[v]=new Edge(u, w, head[v]);
}
}*G;

class UFS
{
private:
int *f;
public:
UFS(int n): f(new int[n+1])
{
for(int i=1; i<=n; ++i)
f[i]=i;
}
~UFS(void)
{
delete[] f;
}
int Find(int x)
{
return x==f[x] ? x : f[x]=Find(f[x]);
}
bool Merge(int x, int y)
{
int a=Find(x), b=Find(y);
if(a==b)
return false;
f[b]=a;
return true;
}
}*S;

class SparseTable
{
private:
int N, **f, **g;
void DFS(int u, int k)
{
G->depth[u]=k;
int v;
for(auto i=G->head[u]; i!=nullptr; i=i->next)
if(!G->depth[v=i->to])
{
f[v][0]=u;
g[v][0]=i->w;
DFS(v, k+1);
}
}
public:
SparseTable(int n): N(log2(n)), f(new int*[n+1]), g(new int*[n+1])
{
for(int i=1; i<=n; ++i)
{
f[i]=new int[N];
g[i]=new int[N];
}
for(int i=1; i<=n; ++i)
if(!G->depth[i])
{
f[i][0]=i;
g[i][0]=INT_MAX;
DFS(i, 1);
}
for(int j=1; j<=N; ++j)
for(int i=1; i<=n; ++i)
{
f[i][j]=f[f[i][j-1]][j-1];
g[i][j]=std::min(g[i][j-1], g[f[i][j-1]][j-1]);
}
}
~SparseTable(void)
{
for(int i=1; i<=n; ++i)
{
delete[] f[i];
delete[] g[i];
}
delete[] f;
delete[] g;
}
int LCA(int x, int y)
{
if(S->Find(x)^S->Find(y))
return -1;
int ans=INT_MAX;
if(G->depth[x]<G->depth[y])
std::swap(x, y);
for(int i=N; i>=0; --i)
if(G->depth[f[x][i]]>=G->depth[y])
{
ans=std::min(ans, g[x][i]);
x=f[x][i];
}
if(x==y)
return ans;
for(int i=N; i>=0; --i)
if(f[x][i]^f[y][i])
{
ans=std::min(ans, std::min(g[x][i], g[y][i]));
x=f[x][i];
y=f[y][i];
}
return ans=std::min(ans, std::min(g[x][0], g[y][0]));
}
}*ST;

void Kruskal(void)
{
std::sort(s+1, s+m+1);
S=new UFS(n);
G=new Graph(n);
for(int i=1; i<=m; ++i)
if(S->Merge(s[i].u, s[i].v))
G->AddEdges(s[i].u, s[i].v, s[i].w);
}

int main(void)
{
scanf("%d %d", &n, &m);
for(int i=1; i<=m; ++i)
s[i].Read();
Kruskal();
ST=new SparseTable(n);
scanf("%d", &q);
for(int i=1, x, y; i<=q; ++i)
{
scanf("%d %d", &x, &y);
printf("%d\n", ST->LCA(x, y));
}
delete S;
delete G;
delete ST;
return 0;
}


posted @ 2018-10-10 21:07  Capella  阅读(188)  评论(4编辑  收藏  举报