zoukankan      html  css  js  c++  java
  • [Codeforces 487E]Tourists

    Description

    题库链接

    给你张 (n) 个点 (m) 条边的连通无向图。 (q) 次操作,让你支持:

    1. 询问可以出现在两点之间的简单路路径上的点的最小权值;
    2. 修改某个点的点权。

    (1leq n, m, qleq 10^5)

    Solution

    显然在路径上如果存在一个点双,那么这个点双上的点是都能被经过的。

    显然我们可以构建圆方树,方点维护点双中所有的点的点权,用堆实现。

    值得注意的是,由于可能一个圆点周围有许多方点,如果更新时在每个方点内都更新的话,复杂度还是不正确的。所以我们规定每个方点只管辖其儿子的圆点。在求 (lca) 处特判一下即可。

    Code

    //It is made by Awson on 2018.3.17
    #include <bits/stdc++.h>
    #define LL long long
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std;
    const int N = 1e5, INF = ~0u>>1;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int X, n, m, q, u, v, a[(N<<1)+5]; char ch[3];
    struct Edge {int u, v; };
    struct Heap {
        priority_queue<int, vector<int>, greater<int> >p, q;
        void erase(int o) {q.push(o); }
        void push(int o) {p.push(o); }
        int top() {while (!q.empty() && p.top() == q.top()) p.pop(), q.pop(); return p.top(); }
    }Q[(N<<1)+5];
    stack<Edge>S;
    int dfn[N+5], low[N+5], sccno[N+5], times, sccnum, pos;
    int fa[(N<<1)+5], size[(N<<1)+5], dep[(N<<1)+5], top[(N<<1)+5], son[(N<<1)+5], idx[(N<<1)+5], b[(N<<1)+5];
    struct graph {
        struct tt {int to, next; }edge[(N<<2)+5];
        int path[(N<<1)+5], top;
        void add(int u, int v) {edge[++top].to = v, edge[top].next = path[u], path[u] = top; }
    }g1, g2;
    struct Segment_tree {
    #define lr(o) (o<<1)
    #define rr(o) (o<<1|1)
        int sgm[(N<<3)+5];
        void build (int o, int l, int r) {
        if (l == r) {sgm[o] = a[b[l]]; return; } int mid = (l+r)>>1;
        build(lr(o), l, mid), build(rr(o), mid+1, r);
        sgm[o] = Min(sgm[lr(o)], sgm[rr(o)]);
        }
        int query(int o, int l, int r, int a, int b) {
        if (a <= l && r <= b) return sgm[o]; int mid = (l+r)>>1;
        int c1 = INF, c2 = INF;
        if (a <= mid) c1 = query(lr(o), l, mid, a, b);
        if (b > mid) c2 = query(rr(o), mid+1, r, a, b);
        return Min(c1, c2);
        }
        void insert(int o, int l, int r, int loc) {
        if (l == r) {sgm[o] = a[b[l]]; return; } int mid = (l+r)>>1;
        if (loc <= mid) insert(lr(o), l, mid, loc); else insert(rr(o), mid+1, r, loc);
        sgm[o] = Min(sgm[lr(o)], sgm[rr(o)]);
        }
    }T;
    
    void tarjan(int o, int fa) {
        dfn[o] = low[o] = ++times;
        for (int i = g1.path[o]; i; i = g1.edge[i].next) {
        int v = g1.edge[i].to;
        if (!dfn[v]) {
            S.push((Edge){o, v});
            tarjan(v, o); low[o] = Min(low[o], low[v]);
            if (low[v] >= dfn[o]) {
            ++n; ++sccnum;
            while (true) {
                Edge e = S.top(); S.pop();
                if (sccno[e.u] != sccnum) sccno[e.u] = sccnum, g2.add(n, e.u), g2.add(e.u, n);
                if (sccno[e.v] != sccnum) sccno[e.v] = sccnum, g2.add(n, e.v), g2.add(e.v, n);
                if (e.u == o && e.v == v) break;                    
            }
            }
        }else if (v != fa) low[o] = Min(low[o], dfn[v]);
        }
    }
    void dfs1(int o, int depth, int father) {
        fa[o] = father, dep[o] = depth, size[o] = 1;
        for (int i = g2.path[o]; i; i = g2.edge[i].next)
        if (g2.edge[i].to != father) {
            if (o >= X) Q[o].push(a[g2.edge[i].to]);
            dfs1(g2.edge[i].to, depth+1, o);
            size[o] += size[g2.edge[i].to];
            if (size[g2.edge[i].to] > size[son[o]]) son[o] = g2.edge[i].to;
        }
        if (o > X) a[o] = Q[o].top();
    }
    void dfs2(int o, int tp) {
        top[o] = tp, idx[o] = ++pos, b[pos] = o;
        if (son[o]) dfs2(son[o], tp);
        for (int i = g2.path[o]; i; i = g2.edge[i].next)
        if (g2.edge[i].to != fa[o] && g2.edge[i].to != son[o])
            dfs2(g2.edge[i].to, g2.edge[i].to);
    }
    int query(int u, int v) {
        int ans = INF, t;
        while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) Swap(u, v);
        t = T.query(1, 1, n, idx[top[u]], idx[u]);
        ans = Min(ans, t); u = fa[top[u]];
        }
        if (dep[u] < dep[v]) Swap(u, v);
        t = T.query(1, 1, n, idx[v], idx[u]); ans = Min(ans, t);
        if (v > X) t = T.query(1, 1, n, idx[fa[v]], idx[fa[v]]), ans = Min(ans, t);
        return ans;
    }
    void update(int o, int val) {
        if (fa[o]) Q[fa[o]].erase(a[o]);
        a[o] = val; T.insert(1, 1, n, idx[o]);
        if (fa[o]) Q[fa[o]].push(a[o]), a[fa[o]] = Q[fa[o]].top(), T.insert(1, 1, n, idx[fa[o]]);
    }
    void work() {
        read(n), read(m), read(q); X = n;
        for (int i = 1; i <= n; i++) read(a[i]);
        for (int i = 1; i <= m; i++) read(u), read(v), g1.add(u, v), g1.add(v, u);
        tarjan(1, 0); dfs1(1, 1, 0); dfs2(1, 1); T.build(1, 1, n);
        while (q--) {
        scanf("%s", ch); read(u), read(v);
        if (ch[0] == 'A') writeln(query(u, v));
        else update(u, v);
        }
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    GitLab → 搭建中常遇的问题与日常维护
    GitLab → 搭建私有的版本控制的托管服务平台
    神奇的 SQL 之 ON 和 WHERE → 扑朔迷离,好多细节!
    神奇的 SQL 之 ICP → 索引条件下推
    神奇的 SQL 之 WHERE 条件的提取与应用
    记一次线上问题 → 事务去哪了
    神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(二)
    神奇的 SQL 之 联表细节 → MySQL JOIN 的执行过程(一)
    python之pip安装mysql-python失败
    python之celery使用详解(二)
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8588195.html
Copyright © 2011-2022 走看看