• 【题解】【CF Round #278】Tourists


      圆方树第二题……

      图中询问的是指定两点之间简单路径上点的最小权值。若我们建出圆方树,圆点的权值为自身权值,方点的权值为所连接的圆点的权值最小值(即点双连通分量中的最小权值)。我们可以发现其实就是这两点在圆方树上经过的点的最小权值,因为在这上面若经过了一个方点,说明可以经过这个点双连通分量中任何一个点并且到达想到的点。(方点所连接的点都是相互可达的)。

      所以问题转化为了求树上两点之间路径的最小点权。并且需要注意的是:链顶的点需要把它的父亲节点也考虑进来,因为它的父亲节点与它是属于同一个双连通分量的。感觉圆方树的好处在这里就可以体现出来:即可以通过一个点来反映出整个点双联通分量的情况,并且相连的方点圆点一定是父子关系,由此可以方便的在树上通过一条路径来总结出很多双联通分量的总情况。

      所以:树剖+可修改堆可以完美解决。

    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 400000
    #define int long long
    #define INF 99999999999
    int n, m, Q, val[maxn];
    int tot, timer, dfn[maxn], low[maxn];
    int cnt, fa[maxn], top[maxn], dep[maxn];
    int S[maxn], size[maxn], hson[maxn];
    
    struct node
    {
        int minn;
        node () { minn = INF; }
    }P[maxn];
    
    struct heap
    {
        priority_queue <int, vector<int>, greater<int> > q1, q2;
        void ins(int x) { q1.push(x); }
        void erase(int x) { q2.push(x); }
        int top()
        {
            while(!q2.empty() && q1.top() == q2.top()) q1.pop(), q2.pop();
            return q1.top();
        }
    }Hp[maxn];
    
    struct edge
    {
        int cnp = 1, head[maxn], to[maxn], last[maxn];
        void add(int u, int v)
        {
            to[cnp] = v, last[cnp] = head[u], head[u] = cnp ++;
            to[cnp] = u, last[cnp] = head[v], head[v] = cnp ++;
        }
    }E1, E2;
    
    int read()
    {
        int x = 0, k = 1;
        char c;
        c = getchar();
        while(c < '0' || c > '9') { if(c == '-') k = -1; c = getchar(); }
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * k;
    }
    
    void Tarjan(int u)
    {
        dfn[u] = low[u] = ++ timer; S[++ S[0]] = u;
        for(int i = E1.head[u]; i; i = E1.last[i])
        {
            int v = E1.to[i];
            if(!dfn[v])
            {
                Tarjan(v); low[u] = min(low[u], low[v]);
                if(low[v] >= dfn[u])
                {
                    E2.add(++ tot, u); int x = 0;
                    do
                    {
                        x = S[S[0] --]; E2.add(tot, x);
                    }while(x != v);
                }
            }
            else low[u] = min(low[u], dfn[v]);
        }
    }
    
    void dfs(int u, int ff)
    {
        fa[u] = ff; dep[u] = dep[ff] + 1; size[u] = 1;
        if(u <= n && ff) Hp[ff].ins(val[u]);
        for(int i = E2.head[u]; i; i = E2.last[i])
        {
            int v = E2.to[i]; if(v == ff) continue;
            dfs(v, u); size[u] += size[v];
            if(size[v] > size[hson[u]]) hson[u] = v;
        } 
    }
    
    void dfs2(int u, int gra)
    {
        dfn[u] = ++ timer; top[u] = gra;
        if(hson[u]) dfs2(hson[u], gra);
        for(int i = E2.head[u]; i; i = E2.last[i])
        {
            int v = E2.to[i]; 
            if(v == fa[u] || v == hson[u]) continue;
            dfs2(v, v);
        }
    }
    
    void update(int p, int l, int r, int x, int num)
    {
        if(l == r) { P[p].minn = num; return; }
        int mid = (l + r) >> 1;
        if(x <= mid) update(p << 1, l, mid, x, num);
        else update(p << 1 | 1, mid + 1, r, x, num);
        P[p].minn = min(P[p << 1].minn, P[p << 1 | 1].minn); 
    }
    
    int query(int p, int l, int r, int L, int R)
    {
        if(l > R || r < L) return INF;
        if(l >= L && r <= R) return P[p].minn;
        int mid = (l + r) >> 1;
        return min(query(p << 1, l, mid, L, R), query(p << 1 | 1, mid + 1, r, L, R));
    }
    
    signed main()
    {
        tot = n = read(), m = read(), Q = read();
        for(int i = 1; i <= n; i ++) val[i] = read();
        for(int i = 1; i <= m; i ++)
        {
            int u = read(), v = read();
            E1.add(u, v);
        }
        for(int i = 1; i <= n; i ++)
            if(!dfn[i]) Tarjan(i);
        timer = 0; dfs(1, 0), dfs2(1, 1);
        for(int i = 1; i <= n; i ++) update(1, 1, tot, dfn[i], val[i]);
        for(int i = n + 1; i <= tot; i ++) update(1, 1, tot, dfn[i], Hp[i].top());
        while(Q --)
        {
            char c; cin >> c; int a = read(), b = read();
            if(c == 'C')
            {
                if(fa[a]) Hp[fa[a]].erase(val[a]);
                val[a] = b; update(1, 1, tot, dfn[a], val[a]);
                if(fa[a]) Hp[fa[a]].ins(val[a]), update(1, 1, tot, dfn[fa[a]], Hp[fa[a]].top());
            }
            else
            {
                int u = a, v = b, ans = INF;
                while(top[u] != top[v])
                {
                    if(dep[top[u]] < dep[top[v]]) swap(u, v);
                    ans = min(ans, query(1, 1, tot, dfn[top[u]], dfn[u]));
                    u = fa[top[u]];
                }
                if(dep[u] > dep[v]) swap(u, v);
                ans = min(ans, query(1, 1, tot, dfn[u], dfn[v]));
                if(u > n) ans = min(ans, val[fa[u]]);
                printf("%lld
    ", ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    通过smtp直接发送邮件
    C# 带参访问接口,WebClient方式
    ASP.NET MVC 中@Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction
    asp.net mvc Html.BeginForm()及Html.Action用法
    Knut重排算法
    C# copy() 与 Clone()区别
    oracle针对某列让特定信息排序[decode]
    oracle 创建表空间详细介绍
    【笔记】.NET开发环境下使用PostgreSQL+Oracle_fdw 实现两个数据库之间数据交互操作(二)
    【笔记】.NET开发环境下使用PostgreSQL+Oracle_fdw 实现两个数据库之间数据交互操作(一)
  • 原文地址:https://www.cnblogs.com/twilight-sx/p/9216802.html
Copyright © 2020-2023  润新知