Codeforces 1253 F - Cheap Robot (최 단 길 + 검색 집합 / Kruskal 트 리)
n 시 m 변 무방 향도, k 개 관건, q 개 질문 (a, b).a 부터 b 까지 필요 한 최소 용량 c 가 얼마 인지 물 어보 세 요.보증 a, b 가 관건 이다.당신 의 에너지 탱크 는 최대 c 에너지 가 있 습 니 다. 걸 을 때마다 변 권 의 그렇게 많은 에 너 지 를 소모 합 니 다.중요 한 점 에서 에 너 지 를 채 울 수 있다.매번 물 어 볼 때마다 필요 한 최소한 의 에너지.k , n ≤ 1 e 5 , q , m ≤ 3 e 5 k,n\le1e5,q,m\le 3e5 k,n≤1e5,q,m≤3e5
문제 풀이 의 사고 방향.
모든 관건 점 을 소스 로 하여 다 원 최 단 로 를 한 번 구하 고 한 점 u u 에 대해 현재 에너지 x < d i s [u] x < dis [u] x < dis [u] x < dis [u] 가 도착 하지 못 할 것 이다. 만약 x > = d i s [u] x > = dis [u] x > = dis [u] 라면 x x x x 는 ≤ c - d i s [u] \ l c - dis [u] ≤ c - dis [u] 의 것 이다.또 x > = d i s [u] x > = dis [u] x > = dis [u] 로 인해 가장 가 까 운 관건 으로 달 려 가 다시 돌아 올 수 있 기 때문에 x 각 점 u 의 에 너 지 는 c - d i s [u] c - dis [u] c - dis [u] 로 유지 할 수 있다.u − > v u - > v u − > v 가 걸 을 수 있 으 려 면 c − d i s [u] − w > = d i s [v] c - dis [u] - w > = dis [v] c − dis [u] - w > = dis [v] 로 전환 하여 d i s [u] + d i s [v] + w ≤ c dis [u] + dis [v] + w \ l c dis [u] + dis [v] + w ≤ c.d i s [u] + d i s [v] + w dis [u] + dis [v] + w dis [u] + dis [v] + w 를 새로운 변 권 으로 새 그림 을 만 듭 니 다.문 제 는 한 점 에서 다른 점 까지 지나 가 는 경로 의 최대 치 를 최소 화 하 는 것 이다.두 가지 방법: 1. 오프라인 방법 은 가중치 에 따라 정렬 한 다음 에 집합 합 니 다.문의 가 점 에 걸 려 있다.처리 해 야 할 문의 수량 에 따라 시작 식 통합 을 진행 합 니 다. 질문 당 최대 l o g log 회 이동 2. 온라인 방법 으로 Kruskal 트 리 를 만 든 후 트 리 에 lca 의 점 권 을 배가 합 니 다.
오프라인 방법:
#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define P pair
using namespace std;
const int maxn = 3e5 + 50;
struct edge{
int u ,v , nxt;
ll w;
bool operator < (const edge &a)const{
return w < a.w;}
}e[maxn*2];
int cnt = 0;
int head[maxn];
void add(int u, int v, ll w){
e[cnt] = (edge){
u, v, head[u], w};
head[u] = cnt++;
}
int n, m, k, Q;
priority_queue<P, vector<P>, greater<P> > q;
ll dis[maxn];
void dij(){
while(q.size()){
P temp = q.top();q.pop();
int u = temp.second;
if(dis[u] < temp.first) continue;
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v; ll w = e[i].w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push(P(dis[v], v));
}
}
}
}
void init(){
memset(head, -1, sizeof head);
cin>>n>>m>>k>>Q;
for(int i = 0; i < m; ++i){
int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
memset(dis, 0x3f, sizeof dis);
for(int i = 1; i <= k; ++i){
dis[i] = 0; q.push(P(0, i));
}dij();
int tp = 0;
for(int i = 0; i < cnt; i += 2){
e[tp] = e[i];
e[tp++].w += dis[e[i].u]+dis[e[i].v];
}
cnt = tp;
}
ll ans[maxn*5];
struct node{
int v, id;};
vector<node> g[maxn];
int fa[maxn];
int fnd(int x){
if(x == fa[x]) return x;
return fa[x] = fnd(fa[x]);
}
void link(int u, int v, ll w){
u = fnd(u); v = fnd(v);
if(u == v) return;
if(g[u].size() > g[v].size()) swap(u, v);
for(int i = 0; i < g[u].size(); ++i){
int x = g[u][i].v;
int id = g[u][i].id;
if(fnd(x) == v)
ans[id] = w;
else
g[v].push_back(g[u][i]);
}
fa[u] = v;
g[u].clear();//g[u].shrink_to_fit(); return;
}
void sol(){
for(int i = 1; i <= n; ++i) fa[i] = i;
for(int i = 0; i < Q; ++i){
int u, v;
scanf("%d%d", &u, &v);
g[u].push_back((node){
v, i});
g[v].push_back((node){
u, i});
}
sort(e, e+cnt);
for(int i = 0; i < cnt; ++i) link(e[i].u, e[i].v, e[i].w);
for(int i = 0; i < Q; ++i) {
printf("%lld
", ans[i]);
}
}
int main()
{
init();
sol();
}
온라인 방법:
#include
#define ll long long
#define lowbit(x) ((x)&(-(x)))
#define mid ((l+r)>>1)
#define lson rt<<1, l, mid
#define rson rt<<1|1, mid+1, r
#define P pair
using namespace std;
const int maxn = 3e5 + 50;
struct edge{
int u ,v , nxt;
ll w;
bool operator < (const edge &a)const{
return w < a.w;}
}e[maxn*2];
int cnt = 0;
int head[maxn];
void add(int u, int v, ll w){
e[cnt] = (edge){
u, v, head[u], w};
head[u] = cnt++;
}
int n, m, k, Q;
priority_queue<P, vector<P>, greater<P> > q;
ll dis[maxn];
void dij(){
while(q.size()){
P temp = q.top();q.pop();
int u = temp.second;
if(dis[u] < temp.first) continue;
for(int i = head[u]; ~i; i = e[i].nxt){
int v = e[i].v; ll w = e[i].w;
if(dis[v] > dis[u] + w){
dis[v] = dis[u] + w;
q.push(P(dis[v], v));
}
}
}
}
void init(){
memset(head, -1, sizeof head);
cin>>n>>m>>k>>Q;
for(int i = 0; i < m; ++i){
int u, v; ll w; scanf("%d%d%lld", &u, &v, &w);
add(u, v, w); add(v, u, w);
}
memset(dis, 0x3f, sizeof dis);
for(int i = 1; i <= k; ++i){
dis[i] = 0; q.push(P(0, i));
}dij();
int tp = 0;
for(int i = 0; i < cnt; i += 2){
e[tp] = e[i];
e[tp++].w += dis[e[i].u]+dis[e[i].v];
}
cnt = tp;
}
ll ans[maxn];
int fa[maxn*2];
int fnd(int x){
if(x == fa[x]) return x;
return fa[x] = fnd(fa[x]);
}
int tot;
vector<int> g[maxn];
ll val[maxn];
int f[maxn][20], dep[maxn];
void get_mst(){
tot = n;
for(int i = 0; i <cnt; ++i){
int u = e[i].u; int v = e[i].v;
u = fnd(u); v = fnd(v); if(u == v) continue;
fa[u] = fa[v] = ++tot; fa[tot] = tot; val[tot] = e[i].w;
g[tot].push_back(v); f[v][0] = tot;
g[tot].push_back(u); f[u][0] = tot;
}
}
void dfs(int u){
for(int i = 0; i+1 < 20; ++i) f[u][i+1] = f[f[u][i]][i];
for(int i = 0; i < g[u].size(); ++i) dep[g[u][i]] =dep[u]+1, dfs(g[u][i]);
}
int lca(int u, int v){
if(dep[u] > dep[v]) swap(u, v);
int d = dep[v] - dep[u]; for(int i = 19; i >= 0; --i) if(d>>i&1) v = f[v][i];
if(u == v) return u;
for(int i = 19; i >= 0; --i){
if(f[u][i] == f[v][i]) continue;
u = f[u][i]; v = f[v][i];
}return f[u][0];
}
void sol(){
for(int i = 1; i <= n; ++i) fa[i] = i;
sort(e, e+cnt);
get_mst();
dfs(tot);
while(Q--){
int u, v; scanf("%d%d", &u, &v);
printf("%lld
", val[lca(u,v)]);
}
}
int main()
{
init();
sol();
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
\# HDU 3790 최 단 경로 문제 [Dijkstra 입문 문제]n 개의 점 을 드 리 겠 습 니 다. m 개의 방향 이 없고 모든 변 에 길이 d 와 소비 p 가 있 습 니 다. 출발점 s 종점 t 를 드 리 겠 습 니 다. 출력 출발점 에서 종점 까지 의 최 단 거리 와 비용...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.