版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题意
给定 T 组样例,
第一行 n 个城市, m 个子公司
接下来的 n-1 行 是城市的边,
再接下来的 m 行, 是子公司按编号 1 到 m 的顺序, g 个工作室, 随后是这 g 个工作室所在城市编号
Q 组询问,
u 子公司, 到 v 子公司 的最短距离
题解
倍增求lca, 在 dfs 更新父节点, 深度 的同时更新距离
对于每一组询问, 枚举一下两个子公司所在的所有城市, 维护最小值.
嗯, 10s 的时间给了我暴力枚举的勇气
貌似还可以 Tarjan 离线法来做, 暂时还没接触过, 等掌握了在写一遍这个题吧
代码
类封装版本
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
class lca_Doubling{
public:
static const int MAXDepth = 20;
static const int MAXN = 1e5+10;
static const int MAXM = 3e5+10; // 有向图双倍加边
struct EDGE {
int v, w, to;
}e[MAXM];
int head[MAXM], cnt = 0; int dis[MAXN];/*dis */
inline void add ( int u, int v, int w ) {
e[cnt].v = v, e[cnt].w = w, e[cnt].to = head[u]; head[u] = cnt++;
}
int up[MAXN][MAXDepth], deep[MAXN];
int n;
lca_Doubling( ) { };
lca_Doubling( int _n ) : n(_n) { };
void ini_graph ( ) {
cnt = 0;
memset ( head, -1, sizeof ( head ) );
/*dis */memset ( dis, 0, sizeof ( dis ) );
memset ( up, 0, sizeof ( up ) );
memset ( deep, 0, sizeof ( deep ) );
}
inline void ini ( int n ) {
this->n = n;
dfs( 1 ); // 开始搜索
up_ini( n ); // 开始预处理
}
private:
void dfs ( int u ) { // 搜索一遍, 记录所有节点的 深度, 距离, 父节点
for ( int k = head[u]; k != -1; k = e[k].to ) {
int v = e[k].v;
if ( v==up[u][0] ) continue;
deep[v] = deep[u]+1;
/*dis */ dis[v] = dis[u]+e[k].w;
up[v][0] = u;
dfs( v );
}
}
void up_ini ( int n ) { // 预处理倍增数组
for ( int j = 1; (1<<j) <= n; ++j )
for ( int i = 1; i <= n; ++i )
up[i][j] = up[up[i][j-1]][j-1];
}
public:
int getAncestor ( int u, int v ) { // 查找最近公共祖先
if ( deep[u]<deep[v] ) swap( u, v );
int d = deep[u]-deep[v];
for ( int i = 0; i < MAXDepth; ++i )
if ( (1<<i)&d )
u = up[u][i];
if ( u == v ) return u;
for ( int i = MAXDepth-1; i >= 0; --i ) {
if ( up[u][i] != up[v][i] ) {
u = up[u][i]; v = up[v][i];
}
}
return up[u][0];
}
inline int getDistance ( int u, int v ) {
return dis[u]+dis[v]-2*dis[getAncestor(u,v)];
}
}lca;
vector<int> c[lca.MAXN];
int main ( ) {
int T,
n, m,
u, v, w,
g, loc,
ans;
sc ( "%d", &T );
while ( T-- ) {
lca.ini_graph( );
sc ( "%d%d", &n, &m );
for ( int i = 1; i < n; ++i ) {
sc ( "%d%d%d", &u, &v, &w );
lca.add ( u, v, w );
lca.add ( v, u, w );
}
for ( int i = 0; i < lca.MAXN; ++i ) c[i].clear ( ); // 初始化子公司的城市位置
for ( int i = 1; i <= m; ++i ) {
sc ( "%d", &g );
while ( g-- ) {
sc ( "%d", &loc );
c[i].push_back ( loc );
}
}
lca.ini( n ); // 初始化 lca
sc ( "%d", &g );
while ( g-- ) {
sc ( "%d%d", &u, &v );
ans = 0x3f3f3f3f;
for ( auto i : c[u] )
for ( auto j : c[v] )
ans = min ( ans, lca.getDistance( i, j) );
pf ( "%d\n", ans );
}
}
return 0;
}
单纯版本
#include <bits/stdc++.h>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
const int MAXN = 1e5+10;
const int MAXM = 3e5+10; // 有向图双倍加边
struct EDGE {
int v, w, to;
}e[MAXM];
int head[MAXM], cnt = 0, dis[MAXN];
inline void add ( int u, int v, int w ) {
e[cnt].v = v, e[cnt].w = w, e[cnt].to = head[u]; head[u] = cnt++;
}
const int MAXDepth = 20;
int up[MAXN][MAXDepth], deep[MAXN];
void dfs ( int u ) { // 搜索一遍, 记录所有节点的 深度, 距离, 父节点
for ( int k = head[u]; k != -1; k = e[k].to ) {
int v = e[k].v;
if ( v==up[u][0] ) continue;
deep[v] = deep[u] + 1;
dis[v] = dis[u]+e[k].w;
up[v][0] = u;
dfs( v );
}
}
void ini ( int n ) { // 预处理倍增数组
for ( int j = 1; (1<<j) <= n; ++j )
for ( int i = 1; i <= n; ++i )
up[i][j] = up[up[i][j - 1]][j - 1];
}
int lca ( int u, int v ) {
if ( deep[u]<deep[v] ) swap( u, v );
int d = deep[u]-deep[v];
for ( int i = 0; i < MAXDepth; ++i )
if ( (1<<i)&d )
u = up[u][i];
if ( u == v ) return u;
for ( int i = MAXDepth-1; i >= 0; --i ) {
if ( up[u][i] != up[v][i] ) {
u = up[u][i]; v = up[v][i];
}
}
return up[u][0];
}
vector<int> c[MAXN];
int main ( ) {
int T,
n, m,
u, v, w,
g, loc,
ans;
sc ( "%d", &T );
while ( T-- ) {
cnt = 0;
memset ( head, -1, sizeof ( head ) );
memset ( dis, 0, sizeof ( dis ) );
memset ( up, 0, sizeof ( up ) );
memset ( deep, 0, sizeof ( deep ) );
for ( int i = 0; i < MAXN; ++i ) c[i].clear ( );
sc ( "%d%d", &n, &m );
for ( int i = 1; i < n; ++i ) {
sc ( "%d%d%d", &u, &v, &w );
add ( u, v, w );
add ( v, u, w );
}
dfs( 1 );
ini ( n );
for ( int i = 1; i <= m; ++i ) {
sc ( "%d", &g );
while ( g-- ) {
sc ( "%d", &loc );
c[i].push_back ( loc );
}
}
sc ( "%d", &g );
while ( g-- ) {
sc ( "%d%d", &u, &v );
ans = 0x3f3f3f3f;
for ( auto i : c[u] )
for ( auto j : c[v] )
ans = min ( ans, dis[i]+dis[j]-2*dis[lca(i,j)] );
pf ( "%d\n", ans );
}
}
return 0;
}