题目来源:
大致题意:
一个树 有n个节点 编号分别为1到n 1号节点是根节点
节点间的边有边权
可以使用特殊跳跃 跳跃权值为p
使用特殊跳跃后 可以从当前节点跳到深度为 当前节点深度+k 的任意节点
问从s点到t点经过的权值和最小是多少
大致思路:
1.记录每个节点深度
用DFS跑图得到每个节点的深度
2.添加虚点
额外添加2*n个点 编号为n+1...n+n 和 2*n+1...2*n+n
添加边
第一组n+i用来离开i层树
树上深度为i的所有节点单向连向n+i号节点 deep:i → n+i
边权皆为0
第二组2*n+i用来进入i层树
树上深度为i的所有节点被2*n+i号节点单向连向 2*n+i → deep:i
边权皆为0
第一组和第二组之间 相差k的相连 用来实现跳跃 边权皆为p
注意:
只用一组原点 相隔k连双向边 会导致同深度的节点间距离错误的变为0
3.跑Dij
AC代码:
#include <bits/stdc++.h>
using namespace std;
using db = long double;
using ll = long long;
#define edl '\n'
#define str string
#define pll pair<ll, ll>
#define fir first
#define sec second
#define heap priority_queue
#define SPO(n) fixed << setprecision(n)
#define FOR(i, l, r) for (long long i = l; i <= r; ++i)
#define ROF(i, r, l) for (long long i = r; i >= l; --i)
#ifdef debugcmd
#define DBG(n) cout << "!!! " << #n << ": " << n << edl
#else
#define DBG(n) ;
#endif
// const long double PI = acos(-1.0);
// const long double EPS = 1.0e-9;
const int INF = 0x3f3f3f3f;
const long long LNF = 0x3f3f3f3f3f3f3f3f;
const long long MOD = 1e9 + 7;
const long long MXN = 3e6 + 5;
struct Dij_Graph
{
ll edgeID;
ll nxt[MXN << 1];
ll head[MXN << 1];
ll tail[MXN << 1];
ll val[MXN << 1];
ll dist[MXN];
bool vis[MXN];
heap<pll, vector<pll>, greater<pll>> he;
void Init(void)
{
edgeID = 0;
memset(head, -1, sizeof(head));
return;
}
void AddEdge(ll u, ll v, ll w)
{
++edgeID;
nxt[edgeID] = head[u];
head[u] = edgeID;
tail[edgeID] = v;
val[edgeID] = w;
return;
}
void Build(ll s)
{
memset(dist, INF, sizeof(dist));
memset(vis, false, sizeof(vis));
while (!he.empty())
he.pop();
dist[s] = 0;
pll tmp;
tmp.fir = 0;
tmp.sec = s;
he.push(tmp);
while (!he.empty())
{
tmp = he.top();
he.pop();
ll id = tmp.sec;
if (vis[id])
continue;
vis[id] = true;
for (ll i = head[id]; i != -1; i = nxt[i])
{
ll j = tail[i];
if (!vis[j] && dist[j] > dist[id] + val[i])
{
dist[j] = dist[id] + val[i];
tmp.fir = dist[j];
tmp.sec = j;
he.push(tmp);
}
}
}
return;
}
ll Query(ll p)
{
if (dist[p] == LNF)
return -1;
return dist[p];
}
};
Dij_Graph g;
ll deep[MXN];
void DFS(ll x, ll fa)
{
for (ll i = g.head[x]; i != -1; i = g.nxt[i])
{
ll j = g.tail[i];
if (j == fa)
continue;
deep[j] = deep[x] + 1;
DFS(j, x);
}
return;
}
void Solve(void)
{
ll n;
cin >> n;
g.Init();
FOR(i, 1, n - 1)
{
ll u, v, w;
cin >> u >> v >> w;
g.AddEdge(u, v, w);
g.AddEdge(v, u, w);
}
deep[1] = 1;
DFS(1, -1);
ll mxDeep = 1;
FOR(i, 1, n)
{
g.AddEdge(i, deep[i] + n, 0);
g.AddEdge(deep[i] + 2 * n, i, 0);
mxDeep = max(mxDeep, deep[i]);
}
ll k, p;
cin >> k >> p;
FOR(i, 1, mxDeep)
{
if (i + k > mxDeep)
break;
g.AddEdge(n + i, 2 * n + i + k, p);
g.AddEdge(n + i + k, 2 * n + i, p);
}
ll s, t;
cin >> s >> t;
g.Build(s);
cout << g.Query(t) << edl;
return;
}
int main(void)
{
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
// #ifdef cincoutcmd
// freopen("cin.txt","r",stdin);
// freopen("cout.txt","w",stdout);
// #endif
ll t;
cin >> t;
while (t--)
Solve();
return 0;
}