mirror of
https://gitcode.com/Zengtudor/alg2025.git
synced 2025-10-29 11:33:03 +00:00
Compare commits
2 Commits
e70c668e57
...
59ad401d66
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59ad401d66 | ||
|
|
218bc31cb3 |
109
src/10/4/AT_abc232_g.cpp
Normal file
109
src/10/4/AT_abc232_g.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const long long INF = 1e18;
|
||||
struct Edge {
|
||||
int to;
|
||||
long long cost;
|
||||
};
|
||||
|
||||
struct State {
|
||||
long long dist;
|
||||
int v;
|
||||
bool operator>(const State &other) const {
|
||||
return dist > other.dist;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
ios_base::sync_with_stdio(false);
|
||||
cin.tie(NULL);
|
||||
|
||||
int N;
|
||||
long long M;
|
||||
cin >> N >> M;
|
||||
|
||||
vector<long long> A(N), B(N);
|
||||
for (int i = 0; i < N; ++i)
|
||||
cin >> A[i];
|
||||
for (int i = 0; i < N; ++i)
|
||||
cin >> B[i];
|
||||
|
||||
vector<pair<long long, int>> sB(N);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
sB[i] = {B[i], i};
|
||||
}
|
||||
sort(sB.begin(), sB.end());
|
||||
|
||||
vector<int> p(N);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
p[i] = sB[i].second;
|
||||
}
|
||||
|
||||
int totnds = 3 * N;
|
||||
vector<vector<Edge>> adj(totnds);
|
||||
|
||||
for (int i = 0; i < N - 1; ++i) {
|
||||
|
||||
adj[N + i + 1].push_back({N + i, sB[i + 1].first - sB[i].first});
|
||||
|
||||
adj[2 * N + i].push_back({2 * N + i + 1, sB[i + 1].first - sB[i].first});
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
|
||||
long long target_b = M - A[i];
|
||||
auto it = lower_bound(sB.begin(), sB.end(), make_pair(target_b, -1));
|
||||
if (it == sB.end()) {
|
||||
it = sB.begin();
|
||||
}
|
||||
int k = distance(sB.begin(), it);
|
||||
adj[i].push_back({N + k, (A[i] + sB[k].first) % M});
|
||||
|
||||
auto it_v = lower_bound(sB.begin(), sB.end(), make_pair(M - A[i], -1));
|
||||
if (it_v != sB.end()) {
|
||||
int k_v = distance(sB.begin(), it_v);
|
||||
adj[i].push_back({N + k_v, (A[i] + sB[k_v].first) - M});
|
||||
}
|
||||
|
||||
adj[i].push_back({2 * N, A[i] + sB[0].first});
|
||||
}
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
adj[N + i].push_back({p[i], 0});
|
||||
adj[2 * N + i].push_back({p[i], 0});
|
||||
}
|
||||
|
||||
vector<long long> dist(totnds, INF);
|
||||
priority_queue<State, vector<State>, greater<State>> pq;
|
||||
|
||||
dist[0] = 0;
|
||||
pq.push({0, 0});
|
||||
|
||||
while (!pq.empty()) {
|
||||
State cur = pq.top();
|
||||
pq.pop();
|
||||
|
||||
long long d = cur.dist;
|
||||
int u = cur.v;
|
||||
|
||||
if (d > dist[u]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto &edge : adj[u]) {
|
||||
if (dist[u] + edge.cost < dist[edge.to]) {
|
||||
dist[edge.to] = dist[u] + edge.cost;
|
||||
pq.push({dist[edge.to], edge.to});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cout << dist[N - 1] << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
242
src/10/5/P1099.cpp
Normal file
242
src/10/5/P1099.cpp
Normal file
@ -0,0 +1,242 @@
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <deque>
|
||||
|
||||
using namespace std;
|
||||
|
||||
const int MAXN = 305;
|
||||
const int INF = 1e9;
|
||||
|
||||
vector<pair<int, int>> adj[MAXN];
|
||||
int n, s;
|
||||
|
||||
int dist[MAXN];
|
||||
int pre[MAXN];
|
||||
bool on_diameter[MAXN];
|
||||
|
||||
// BFS 用于找最远点和记录路径
|
||||
void bfs(int start_node, int& farthest_node, bool record_path) {
|
||||
fill(dist, dist + n + 1, -1);
|
||||
if (record_path) {
|
||||
fill(pre, pre + n + 1, 0);
|
||||
}
|
||||
|
||||
deque<int> q;
|
||||
q.push_back(start_node);
|
||||
dist[start_node] = 0;
|
||||
|
||||
int max_dist = 0;
|
||||
farthest_node = start_node;
|
||||
|
||||
while (!q.empty()) {
|
||||
int u = q.front();
|
||||
q.pop_front();
|
||||
|
||||
if (dist[u] > max_dist) {
|
||||
max_dist = dist[u];
|
||||
farthest_node = u;
|
||||
}
|
||||
|
||||
for (auto& edge : adj[u]) {
|
||||
int v = edge.first;
|
||||
int w = edge.second;
|
||||
if (dist[v] == -1) {
|
||||
dist[v] = dist[u] + w;
|
||||
if (record_path) {
|
||||
pre[v] = u;
|
||||
}
|
||||
q.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DFS 计算直径上节点的分支长度
|
||||
int max_branch_len;
|
||||
void dfs(int u, int p, int current_dist) {
|
||||
max_branch_len = max(max_branch_len, current_dist);
|
||||
for (auto& edge : adj[u]) {
|
||||
int v = edge.first;
|
||||
int w = edge.second;
|
||||
if (v != p && !on_diameter[v]) {
|
||||
dfs(v, u, current_dist + w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
ios_base::sync_with_stdio(false);
|
||||
cin.tie(NULL);
|
||||
|
||||
cin >> n >> s;
|
||||
for (int i = 0; i < n - 1; ++i) {
|
||||
int u, v, w;
|
||||
cin >> u >> v >> w;
|
||||
adj[u].push_back({v, w});
|
||||
adj[v].push_back({u, w});
|
||||
}
|
||||
|
||||
// Step 1: 找直径
|
||||
int u_diam, v_diam;
|
||||
bfs(1, u_diam, false);
|
||||
bfs(u_diam, v_diam, true);
|
||||
|
||||
vector<int> diameter_nodes;
|
||||
int current = v_diam;
|
||||
while (current != 0) {
|
||||
diameter_nodes.push_back(current);
|
||||
on_diameter[current] = true;
|
||||
current = pre[current];
|
||||
}
|
||||
reverse(diameter_nodes.begin(), diameter_nodes.end());
|
||||
|
||||
int k = diameter_nodes.size();
|
||||
vector<int> diam_dist(k); // dist from u_diam
|
||||
vector<int> r(k); // max branch length
|
||||
|
||||
// Step 2: 计算分支长度
|
||||
vector<int> temp_dist(n + 1);
|
||||
deque<int> q_dist;
|
||||
|
||||
fill(temp_dist.begin(), temp_dist.end(), -1);
|
||||
q_dist.push_back(u_diam);
|
||||
temp_dist[u_diam] = 0;
|
||||
|
||||
int head = 0;
|
||||
while(head < q_dist.size()){
|
||||
int u = q_dist[head++];
|
||||
for(auto& edge : adj[u]){
|
||||
int v = edge.first;
|
||||
int w = edge.second;
|
||||
if(temp_dist[v] == -1){
|
||||
temp_dist[v] = temp_dist[u] + w;
|
||||
q_dist.push_back(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < k; ++i) {
|
||||
diam_dist[i] = temp_dist[diameter_nodes[i]];
|
||||
max_branch_len = 0;
|
||||
dfs(diameter_nodes[i], 0, 0);
|
||||
r[i] = max_branch_len;
|
||||
}
|
||||
|
||||
// Step 3: 滑动窗口求解
|
||||
int ans = INF;
|
||||
deque<int> q_max_r;
|
||||
int left = 0;
|
||||
|
||||
for (int right = 0; right < k; ++right) {
|
||||
while (diam_dist[right] - diam_dist[left] > s) {
|
||||
if (!q_max_r.empty() && q_max_r.front() == left) {
|
||||
q_max_r.pop_front();
|
||||
}
|
||||
left++;
|
||||
}
|
||||
|
||||
while (!q_max_r.empty() && r[q_max_r.back()] <= r[right]) {
|
||||
q_max_r.pop_back();
|
||||
}
|
||||
q_max_r.push_back(right);
|
||||
|
||||
int ecc_in = r[q_max_r.front()];
|
||||
|
||||
// 考虑核外侧的部分
|
||||
// 简化版本:只考虑直径两端到核的距离
|
||||
int ecc_out = max(diam_dist[left], diam_dist[k - 1] - diam_dist[right]);
|
||||
|
||||
ans = min(ans, max(ecc_in, ecc_out));
|
||||
}
|
||||
|
||||
// 补充:上面的 ecc_out 是一个简化,可能不完全正确。
|
||||
// 在一些情况下,最远点可能来自直径中间某个点的大分支。
|
||||
// 但对于这道题的数据范围和性质,这个简化做法可以通过。
|
||||
// 一个更严谨(但也更慢)的做法是遍历所有不在当前窗口的点,计算其到窗口的距离。
|
||||
// 完整做法是预处理,但更复杂。最终答案是所有点到核的距离的最大值。
|
||||
// 我们已经计算了窗口内的最大分支,现在要加上窗口外的。
|
||||
|
||||
int final_ans = ans;
|
||||
for(int i = 0; i < k; ++i) {
|
||||
final_ans = max(final_ans, r[i]);
|
||||
}
|
||||
|
||||
// 我们要找的是所有点到核的最大距离。
|
||||
// 我们滑动窗口找到的 `ans` 是 `min(max(ecc_in, ecc_out))`
|
||||
// `ecc_out` 应该包含所有核外的点。
|
||||
for (int i = 0; i < left; ++i) {
|
||||
ans = max(ans, r[i] + diam_dist[left] - diam_dist[i]);
|
||||
}
|
||||
for (int i = k-1; i >=0 && diam_dist[i] - diam_dist[left] > s ; --i) {
|
||||
// Find the rightmost node `j` for the current `left`
|
||||
int j = -1;
|
||||
int low = left, high = k-1, best_j = left;
|
||||
while(low <= high){
|
||||
int mid = low + (high-low)/2;
|
||||
if(diam_dist[mid] - diam_dist[left] <= s){
|
||||
best_j = mid;
|
||||
low = mid + 1;
|
||||
} else {
|
||||
high = mid-1;
|
||||
}
|
||||
}
|
||||
j = best_j;
|
||||
|
||||
// Recalculate ans for this window [left, j]
|
||||
int current_max_r = 0;
|
||||
for(int l = left; l <= j; ++l) current_max_r = max(current_max_r, r[l]);
|
||||
|
||||
int current_ecc_out = 0;
|
||||
for(int l=0; l<left; ++l) current_ecc_out = max(current_ecc_out, r[l] + diam_dist[left] - diam_dist[l]);
|
||||
for(int l=j+1; l<k; ++l) current_ecc_out = max(current_ecc_out, r[l] + diam_dist[l] - diam_dist[j]);
|
||||
|
||||
final_ans = min(final_ans, max(current_max_r, current_ecc_out));
|
||||
}
|
||||
|
||||
// The double loop is too slow. The initial sliding window logic is actually what's needed.
|
||||
// Let's re-verify the logic.
|
||||
// For a window [left, right], ecc is max(max_r_in_window, max_dist_from_outside)
|
||||
// max_dist_from_outside = max(dist_from_left_side, dist_from_right_side)
|
||||
// dist_from_left_side = max_{i < left} (r_i + dist(p_left) - dist(p_i))
|
||||
// This needs precomputation.
|
||||
|
||||
vector<int> L(k), R(k);
|
||||
vector<int> pref_L(k), suff_R(k);
|
||||
|
||||
for(int i = 0; i < k; ++i) L[i] = r[i] - diam_dist[i];
|
||||
for(int i = 0; i < k; ++i) R[i] = r[i] + diam_dist[i];
|
||||
|
||||
pref_L[0] = L[0];
|
||||
for(int i = 1; i < k; ++i) pref_L[i] = max(pref_L[i-1], L[i]);
|
||||
|
||||
suff_R[k-1] = R[k-1];
|
||||
for(int i = k-2; i >= 0; --i) suff_R[i] = max(suff_R[i+1], R[i]);
|
||||
|
||||
left = 0;
|
||||
ans = INF;
|
||||
q_max_r.clear();
|
||||
|
||||
for (int right = 0; right < k; ++right) {
|
||||
while (diam_dist[right] - diam_dist[left] > s) {
|
||||
if (!q_max_r.empty() && q_max_r.front() == left) {
|
||||
q_max_r.pop_front();
|
||||
}
|
||||
left++;
|
||||
}
|
||||
while (!q_max_r.empty() && r[q_max_r.back()] <= r[right]) {
|
||||
q_max_r.pop_back();
|
||||
}
|
||||
q_max_r.push_back(right);
|
||||
|
||||
int term1 = r[q_max_r.front()];
|
||||
int term2 = (left > 0) ? (pref_L[left - 1] + diam_dist[left]) : 0;
|
||||
int term3 = (right < k - 1) ? (suff_R[right + 1] - diam_dist[right]) : 0;
|
||||
|
||||
ans = min(ans, max({term1, term2, term3}));
|
||||
}
|
||||
|
||||
cout << ans << endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user