首页 > 其他分享 >P3573 [POI2014]RAJ-Rally 题解

P3573 [POI2014]RAJ-Rally 题解

时间:2023-04-29 11:55:22浏览次数:39  
标签:disS int 题解 top RAJ del disF Rally void

非常好题目,爱来自 xc。


  • 看到有向无环图,想到拓扑序。通过拓扑序,可以轻松求出以每个点为起点的最长路 \(disS\)与每个点为终点的最长路 \(disF\)。

  • 如何求总共的最长路?在 \(disS,disF,disS_u + 1 + disF_v((u,v)\in E)\) 中取最大值即可。注意最后一项,表示将连边的二点值相加。

  • 如何处理删点?删掉一个点后,有一些点的 \(disS\) 不会变,有一些点的 \(disT\) 不会变。我们不妨把这两类点进行分组,得到组 \(A\) 和组 \(B\)。

  • 为什么要进行分组?因为第三类取值 \(disS_u + 1 + disF_v\) 只会在两组间连边产生,且 \(u\in A,v\in B\)。因为只有此时 \(disS_u\) 和 \(disF_v\) 才不会受删点影响。

  • 发现 \(A\) 与 \(B\) 的单次加减是简单的,于是我们考虑递推每一个答案。

  • 若当前求的点为 \(u\),不妨认为在这之后我们会将 \(u\) 从 \(B\) 中加入 \(A\) 中。那么我们要删除 \(disF_u\) 以及所有包含 \(disF_u\) 的第三类值,同时加入 \(disS_u\) 与所有包含 \(disS_u\) 的第三类值。此时最大值就是答案。

  • 注意到上述过程需要满足当加入 \(u\) 时,所有 \(u\) 连向的点还在 \(B\) 内。因此递推的顺序是翻转的拓扑序。

  • 删除加入求最大值可以用优先队列解决,由于一次就写过了不知道有什么需要注意的点。

#include<bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;

template<typename T> bool chkmax(T &a, T b) { return a < b ? (a = b, 1) : 0; }
template<typename T> bool chkmin(T &a, T b) { return a > b ? (a = b, 1) : 0; }

int n, m;
namespace Graph {
    template<const int M> 
    struct graph {
        int st[M], nx[M << 1], to[M << 1], cnt;
        void add(int u, int v) { to[++cnt] = v;nx[cnt] = st[u];st[u] = cnt; }
    };
    #define go(g, u, v) for (int i = g.st[u], v = g.to[i]; i; i = g.nx[i], v = g.to[i])
    graph<N << 1> g, ig;

    int in[N], out[N], hisI[N], hisO[N];
    bool vis[N];
    void add(int u, int v) {
        g.add(u, v);
        ig.add(v, u);
        vis[u] = vis[v] = true;
        ++hisI[v];++hisO[u];
        ++in[v];++in[u];
    }
    void init() {
        for (int i = 1; i <= n; ++i) in[i] = hisI[i], out[i] = hisO[i];
    }

    vector<int> A, B;
    int disS[N], disF[N];
    void findS() {
        init();
        queue<int> q;
        for (int i = 1; i <= n; ++i) if (out[i] == 0 && vis[i] == true) q.push(i);
        while (!q.empty()) {
            int u = q.front();q.pop();
            A.push_back(u);
            go (ig, u, v) {
                if (--out[v] == 0) q.push(v);
                chkmax(disS[v], disS[u] + 1);
            }
        } 
        for (int i = A.size() - 1; i >= 0; --i) B.push_back(A[i]);
    }
    void findF() {
        init();
        queue<int> q;
        for (int i = 1; i <= n; ++i) if (in[i] == 0) q.push(i);
        while (!q.empty()) {
            int u = q.front();q.pop();
            go (g, u, v) {
                if (--in[v] == 0) q.push(v);
                chkmax(disF[v], disF[u] + 1);
            }
        }
    }

    struct Pqueue {
        priority_queue<int> q, del;
        void push(int x) { q.push(x); }
        void pop(int x) { del.push(x); }
        int top() { 
            while (!del.empty() && q.top() == del.top()) q.pop(), del.pop();
            return q.top();
        }
        int size() {
            while (!del.empty() && q.top() == del.top()) q.pop(), del.pop();
            return q.size();
        } 
    }Q;

    pair<int, int> work() {
        int ans = 2147483647, id = 0;
        for (int i = 1; i <= n; ++i) Q.push(disS[i]);
        for (auto u : B) {
            Q.pop(disS[u]);
            go (ig, u, v) Q.pop(disF[v] + 1 + disS[u]);
            if (chkmin(ans, Q.top())) id = u;
            go (g, u, v) Q.push(disF[u] + 1 + disS[v]);
            Q.push(disF[u]);
        }
        return make_pair(id, ans);
    }
}
int main() {
    freopen("text.in", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);

    cin >> n >> m;
    for (int i = 1, u, v; i <= m; ++i) {
        cin >> u >> v;
        Graph::add(u, v);
    }

    Graph::findS();
    Graph::findF();

    pair<int, int> ans = Graph::work();
    cout << ans.first << ' ' << ans.second << endl;

    return 0;
}

标签:disS,int,题解,top,RAJ,del,disF,Rally,void
From: https://www.cnblogs.com/closureshop/p/P3573.html

相关文章

  • 题解 CF1264D1
    前言数学符号约定:\(\dbinom{n}{m}\):表示\(n\)选\(m\)。如非特殊说明,将会按照上述约定书写符号。题目分析:考虑题目的问题弱一点的版本,假设此时我们的括号序列是确定的如何求其括号匹配的最深深度。如果你有些许dp基础的话,不难想到如下做法:考虑位置\(i\),将区间\([1,......
  • 题解 CF1264D2
    前言建议大家看一下我对于D1的题解(传送门)后再看本题解,本题解是基于那篇题解的基础上书写的。数学符号约定\(\dbinom{n}{m}\):表示\(n\)选\(m\)。如非特殊说明,将会按照上述约定书写符号。题目分析首先引用一下D1的答案:\(\displaystyle\sum_{i=1}^n\displaystyle\sum_{......
  • [ARC125E] Snack 题解
    不难发现一个较简单的网络流模型:源点向所有糖果\(i\)连\(a_i\)的容量;所有糖果向所有人\(i\)连\(b_i\)的容量;所有人\(i\)向汇点连\(c_i\)的容量。但第二步中建出的边数达到了惊人的\(O(nm)\),显然过不去。考虑优化。从最大流角度优化较困难,由于最大流等价于最小......
  • P4423 题解
    前言题目传送门!更好的阅读体验?刚学分治就来写篇题解纪念一下,其实和平面最近点对一样的(总共四倍经验!)。思路根据P7883的分治思路,这题我们可以考虑用相似的方法解决。首先将点集按\(x\)坐标从小到大排序。然后分治。对于\(\left[l,r\right]\)区间,分治为\(\left[l,mid......
  • 题解 P3225 [HNOI2012] 矿场搭建
    解析传送门一道简单的tarjan题题意:在无向图中找一些点,这些点组成的的点集记为\(V\),使得去掉任意一个点,剩下的每一个点都可以到达\(V\)中任意一个点,求点集\(V\)的大小的最小值及其方案数。去掉一个点,很自然的联想到割点,那么考虑一下割点在不在备选集合中。如图,显然可以看出,......
  • Codeforces Round 868 (Div. 2) A-E题解
    比赛地址这把真不在状态,麻了,看来还得再练A.A-characteristic题意:给出n和k,要求构造只含1和-1数组a,存在k对(i,j)(i≠j),有a[i]*a[j]=1Solution令构造的数组有x个1和y个-1,那么其对于答案的贡献有\[x*(x-1)/2+y*(y-1)/2\]又因为有x+y=n,所以可以转化成关于x的一元二次方程化简后......
  • COMPSCI 589 问题解答
    COMPSCI589Homework4-Spring2023DueMay6,2023,11:55pmEasternTime1InstructionsThishomeworkassignmentconsistsofaprogrammingportion.Whileyoumaydiscussproblemswithyourpeers,youmustanswerthequestionsonyourownandimplementall......
  • P4681 [THUSC2015]平方运算 题解
    题面链接简要题意给定一个序列,区间.map([](intx){x=x*x%p;});,区间求和。p给定,为小质数。\(N,M\le10^5\)。题解而把一个数看作一个点,向其平方取模连一条边,则最终必然构成一个基环森林,注意到\(P\)很小,每个数经过\(11\)次迭代之后就会进入环中。对于一个区间,如......
  • “makefile:425: *** 遗漏分隔符 。 停止。”问题解决
    在终端下输入make时出现“makefile:2:***遗漏分隔符。停止。”问题,原因是在编写makefile文件时:3:3.c        gcc-o33.cgcc前的是tab分隔符,不能用空格,否则会出现“makefile:2:***遗漏分隔符。停止。”提示。。。make中规定每一Shell命令之前的开头必须使用<t......
  • 题解(开始学知识点
    D.FrogTraveler1900dpgq!https://codeforces.com/contest/1602/problem/D题解:我们可以通过类似bfs的过程找到每个点的能到达的所需步数最小的点,完成更新,但每个点能被哪些点到达很难判断,故我们反过来考虑,如果我们能得到从n->0的最短跳跃次数,亦得解,而每个点下一步能到达的点容......