专栏文章

P8240

P8240题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miocc7vi
此快照首次捕获于
2025/12/02 16:53
3 个月前
此快照最后确认于
2025/12/02 16:53
3 个月前
查看原文
整体二分。
先求出来点 ii 到守卫最近的距离 disidis_i,然后二分 xx
然后问题就变成了是否可以只经过 disi>xdis_i>x 的点从 SSTT
点权不好维护,改成边权的形式,每条边 (u,v)(u,v) 边权为 min(disu,disv)\min(dis_u,dis_v),二分时只连满足 min(disu,disv)>x\min(dis_u,dis_v)>x 的边 (u,v)(u,v)。然后就是判断 S,TS,T 是否连通,用并查集维护。
然后这个 QQ 次询问复杂度是 O(QnlognlogV)O(Qn\log n\log V) 的,可以用整体二分优化到 O(nlogn+QlognlogV)O(n\log n+Q\log n\log V)。注意整体二分的时候会对并查集进行撤销操作,因此用可撤销并查集。
CPP
constexpr int N = 1e5 + 5;
ll dis[N];
int n, m, k, Q;

struct Info {
    ll x, dis;
    bool operator <(const Info& p) const {
        return dis > p.dis;
    }
} ;

struct Hidesuwa {
    int fa[N << 1], dep[N << 1];
    stack <tuple <int, int, int> > s;

    void Init () {
        F (i, 1, n << 1 | 1) fa[i] = i, dep[i] = 1;
    }

    int Find (int x) {
        if (x == fa[x]) return x;
        return Find (fa[x]);
    }

    int Merge (int x, int y) {
        int rx = Find (x), ry = Find (y);
        if (rx == ry) return 0;
        int dx = dep[rx], dy = dep[ry];
        if (dx > dy) swap (x, y), swap (rx, ry), swap (dx, dy);
        s.push ({rx, ry, dy});
        fa[rx] = ry, dep[ry] = max (dx + 1, dy);
        return 1;
    }

    void Rm () {
        auto [x, y, d] = s.top (); s.pop ();
        fa[x] = x, dep[y] = d;
    }
} st;

priority_queue <Info> q;

vector <pair <int, ll> > e[N];

tuple <int, int, ll> t[N << 1];
int p[N];
bitset <N> vis;

void Dijkstra () {
    F (i, 1, n) dis[i] = inf;
    F (i, 1, k) dis[p[i]] = 0;
    F (i, 1, k) {
        q.push ({p[i], 0});
    }
    while (! q.empty ()) {
        auto [u, d1] = q.top (); q.pop ();
        d1 = dis[u];
        if (vis[u] == 1) continue;
        vis[u] = 1;
        for (auto [v, d2] : e[u]) {
            if (dis[v] > d1 + d2) {
                dis[v] = d1 + d2;
                if (! vis[v]) q.push ({v, d1 + d2});
            }
        }
    }
}
ll ans[N];
void Work (vector <tuple <int, int, int> > v, int s, ll L, ll R) {
    if (L == R || ! v.size ()) {
        F (i, s, m) {
            auto [x, y, d] = t[i];
            if (d >= L) st.Merge (x, y);
            else break;
        }
        for (auto [x, y, id] : v) ans[id] = L;
        return ;
    }
    ll m = (L + R + 1) >> 1;
    int cnt = 0, pos = s - 1;
    F (i, s, :: m) {
        auto [x, y, d] = t[i];
        if (d >= m) cnt += st.Merge (x, y);
        else {
            pos = i - 1; break;
        }
    }
    vector <tuple <int, int, int> > v0, v1;
    for (auto [x, y, id] : v) {
        if (st.Find (x) == st.Find (y)) v0.push_back ({x, y, id});
        else v1.push_back ({x, y, id});
    }
    F (i, 1, cnt) st.Rm ();
    Work (v0, s, m, R);
    Work (v1, pos + 1, L, m - 1);
}

int main () {
    OPEN
    IOS
    cin >> n >> m;
    F (i, 1, m) {
        int x, y; ll d; cin >> x >> y >> d;
        e[x].push_back ({y, d}), e[y].push_back ({x, d});
        t[i] = {x, y, 0};
    }
    cin >> k;
    F (i, 1, k) cin >> p[i]; 
    Dijkstra (); st.Init ();
    F (i, 1, m) {
        auto [x, y, _] = t[i];
        t[i] = {x, y, min (dis[x], dis[y])};
    }
    sort (t + 1, t + m + 1, [] (tuple <int, int, ll> t1, tuple <int, int, ll> t2) {
        auto [x1, y1, d1] = t1;
        auto [x2, y2, d2] = t2;
        return d1 > d2;
    }) ;
    vector <tuple <int, int, int> > q;
    cin >> Q;
    F (i, 1, Q) {
        int s, t; cin >> s >> t;
        q.push_back ({s, t, i});
    }
    Work (q, 1, 0, (ll) (1e14));
    F (i, 1, Q) cout << max (ans[i] - 1, 0LL) << '\n';
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...