zoukankan      html  css  js  c++  java
  • "中国东信杯"广西大学第二届程序设计竞赛

    题意:给一个有向图,n个点m条边,每个点有点权xi。规定从u点出发,到指定的k个点之一结束,可以多次经过同一个点和同一条边,求路径上点权和的最大值。

    题解:直接缩点变成DAG,然后dp的时候并不是直接往父亲上面加,比如下面的4个点4条边的图:

    4 4
    1 2
    1 3
    2 4
    3 4
    

    直接往父亲上面加会导致x[4]出现了两次。

    注意到这个其实是DAG,拓扑的时候把自己的值尝试更新给父亲,父亲保留所有儿子之中的最大值就可以了。

    又交又WA,忘记考虑结束点的情况了。只有当这个儿子的答案中携带结束点的时候才往父亲更新,同时设置父亲的答案也是携带有结束点。

    又交又T,板子里有个排序去重,5e5居然不能nlogn,好吧,それは私の過ちです。

    namespace SCC {
        const int MAXN = 5e5;
    
        int n;
        vector<int> G[MAXN + 5];
        vector<int> BG[MAXN + 5];
    
        int c1[MAXN + 5], cntc1;
        int c2[MAXN + 5], cntc2;
        int s[MAXN + 5], cnts;
    
        int n2;
        vector<int> V2[MAXN + 5];
        //vector<int> G2[MAXN + 5];
        vector<int> BG2[MAXN + 5];
    
        ll val[MAXN + 5];
        ll val2[MAXN + 5];
        bool ok[MAXN + 5];
        bool ok2[MAXN + 5];
    
        void Init(int _n) {
            n = _n;
            cntc1 = 0, cntc2 = 0, cnts = 0;
            for(int i = 1; i <= n; ++i) {
                G[i].clear();
                BG[i].clear();
                c1[i] = 0;
                c2[i] = 0;
                s[i] = 0;
                V2[i].clear();
                //G2[i].clear();
                BG2[i].clear();
                val[i] = 0;
                val2[i] = 0;
                ok[i] = 0;
                ok2[i] = 0;
            }
        }
    
        void AddEdge(int u, int v) {
            G[u].push_back(v);
            BG[v].push_back(u);
        }
    
        void dfs1(int u) {
            c1[u] = cntc1;
            for(int v : G[u]) {
                if(!c1[v])
                    dfs1(v);
            }
            s[++cnts] = u;
        }
    
        void dfs2(int u) {
            V2[cntc2].push_back(u);
            val2[cntc2] += val[u];
            ok2[cntc2] |= ok[u];
            c2[u] = cntc2;
            for(int v : BG[u]) {
                if(!c2[v])
                    dfs2(v);
            }
        }
    
        void Kosaraju() {
            for(int i = 1; i <= n; ++i) {
                if(!c1[i]) {
                    ++cntc1;
                    dfs1(i);
                }
            }
    
            for(int i = n; i >= 1; --i) {
                if(!c2[s[i]]) {
                    ++cntc2;
                    dfs2(s[i]);
                }
            }
        }
    
        void Build() {
            n2 = cntc2;
            for(int i = 1; i <= n2; ++i) {
                for(auto u : V2[i]) {
                    for(auto v : G[u]) {
                        if(c2[v] != i) {
                            //G2[i].push_back(c2[v]);
                            BG2[c2[v]].push_back(i);
                        }
                    }
                }
            }
    
            for(int i = 1; i <= n2; ++i) {
                //sort(G2[i].begin(), G2[i].end());
                //G2[i].erase(unique(G2[i].begin(), G2[i].end()), G2[i].end());
                //sort(BG2[i].begin(), BG2[i].end());
                //BG2[i].erase(unique(BG2[i].begin(), BG2[i].end()), BG2[i].end());
            }
        }
    
    
        void Solve(int u) {
            for(int i = n2; i >= 1; --i) {
                val[i] = 0;
                ok[i] = ok2[i];
            }
            for(int i = n2; i >= 1; --i) {
                ok[i] |= ok2[i];
                if(ok[i])
                    val[i] += val2[i];
                for(auto &v : BG2[i]) {
                    if(ok[i]) {
                        val[v] = max(val[v], val[i]);
                        ok[v] = 1;
                    }
                }
            }
            printf("%lld
    ", val[c2[u]]);
        }
    }
    
    void test_case() {
        int n, m;
        scanf("%d%d", &n, &m);
        SCC::Init(n);
        while(m--) {
            int u, v;
            scanf("%d%d", &u, &v);
            SCC::AddEdge(u, v);
        }
        for(int i = 1; i <= n; ++i)
            scanf("%lld", &SCC::val[i]);
        int u, k;
        scanf("%d%d", &u, &k);
        while(k--) {
            int v;
            scanf("%d", &v);
            SCC::ok[v] = 1;
        }
        SCC::Kosaraju();
        SCC::Build();
        SCC::Solve(u);
    }
    
  • 相关阅读:
    怎样判断数组类型
    VS2017不能生成Database Unit Test项目
    Windows Server 远程桌面报错:No Remote Desktop License Servers Available
    TFS2018 获取所有Build变量及变量值
    C# 读写bat文件
    【PowerShell 学习系列】-- 删除Win10自带应用
    Win10
    【TFS】TFS2015链接TFS出现TF31002/TF400324问题解决方案
    【SQL Server 学习系列】-- 获取字符串中出现某字符的次数及字符某次出现的下标
    【.Net 学习系列】-- 利用Aspose转换Excel为PDF文件
  • 原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12006310.html
Copyright © 2011-2022 走看看