zoukankan      html  css  js  c++  java
  • bzoj3832

    拓扑排序+set

    如果我们直接记录所有路径是不行的,那么我们要降低路径的数量,于是我们把最短路径转换到边上,这样我们就只有m条路径了。

    先计算出f[i]和g[i]表示正反拓扑最长链,把所有g插到set里,然后按照拓扑序依次枚举删点,把之前加入过的边删除,删除g[u],查询最大值,然后加入后继边每条边的权值就是f[x]+g[to]+1,再加入f[u]这样我们按照拓扑序就不用加入之前删掉的边,因为我们是按照拓扑序删的,这样后面删的点肯定会影响之前的最长链,如果不影响则说明最长链已经被枚举完了,所以之前的最长链自然也受影响。

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 5e5 + 5;
    int n, m, tot, ans = 0x3f3f3f3f, p;
    vector<int> G[N], rev[N];
    int in[N], a[N], f[N], g[N];
    int rd()
    {
        int x = 0, f = 1; char c = getchar();
        while(c < '0' || c > '9') { if(c == '-') f = -1; c = getchar(); }
        while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
        return x * f;
    } 
    multiset<int> s;
    int main() 
    {
        n = rd();
        m = rd();
        for(int i = 1; i <= m; ++i) 
        {
            int u = rd(), v = rd();
            G[u].push_back(v);
            rev[v].push_back(u);
            ++in[v];
        }       
        queue<int> q;
        for(int i = 1; i <= n; ++i) if(in[i] == 0) q.push(i);
        while(!q.empty()) 
        {
            int u = q.front();
            a[++tot] = u;
            q.pop();
            for(int i = 0; i < G[u].size(); ++i) 
            {
                int v = G[u][i];
                f[v] = max(f[v], f[u] + 1);
                if(--in[v] == 0) q.push(v);
            }
        }
        for(int i = n; i; --i) 
        {
            int u = a[i];
            for(int j = 0; j < rev[u].size(); ++j) 
            {
                int v = rev[u][j];
                g[v] = max(g[v], g[u] + 1);
            }
        }
        for(int i = 1; i <= n; ++i) s.insert(g[i]);
        for(int i = 1; i <= n; ++i) 
        {
            int u = a[i];       
            multiset<int> :: iterator it;
            it = s.find(g[u]);
            if(it != s.end()) s.erase(it);
            for(int j = 0; j < rev[u].size(); ++j) 
            {
                it = s.find(f[rev[u][j]] + g[u] + 1);
                s.erase(it);
            }
            if(!s.empty()) if(*(s.rbegin()) < ans) ans = *(s.rbegin()), p = u;
            for(int j = 0; j < G[u].size(); ++j) 
                s.insert(g[G[u][j]] + f[u] + 1);
            s.insert(f[u]);
        }
        printf("%d %d
    ", p, ans);
        return 0;
    }
    
    View Code
  • 相关阅读:
    HDU 5213 分块 容斥
    HDU 2298 三分
    HDU 5144 三分
    HDU 5145 分块 莫队
    HDU 3938 并查集
    HDU 3926 并查集 图同构简单判断 STL
    POJ 2431 优先队列
    HDU 1811 拓扑排序 并查集
    HDU 2685 GCD推导
    HDU 4496 并查集 逆向思维
  • 原文地址:https://www.cnblogs.com/19992147orz/p/7911789.html
Copyright © 2011-2022 走看看