Luogu P43916 图的遍历

我们把“u点能够到达的最大点”转化为反向图中能到达u点的所有点里的最大值,可知缩点后满足无后效性。val[i]的初值设为连通分量i中的最大点。反向存图,tarjan缩点,拓扑序dp即可。

  1. #include <iostream>  
  2. #include <cstdio>  
  3. #include <queue>  
  4. #define maxn 100100  
  5. using namespace std;   
  6. int n, m;  
  7. void read(int &x) {  
  8.     x = 0;  
  9.     char ch = getchar();  
  10.     while (!isdigit(ch))  
  11.         ch = getchar();  
  12.     while (isdigit(ch))  
  13.         x = x * 10 + (ch ^ 48),  
  14.         ch = getchar();  
  15.     return;  
  16. }  
  17. struct E {  
  18.     int to, nxt;  
  19. } edge[maxn], edge2[maxn];  
  20. int head[maxn], top, head2[maxn], top2;  
  21. inline void insert(int u, int v) {  
  22.     edge[++top] = (E) {v, head[u]};  
  23.     head[u] = top;  
  24. }  
  25. inline void insert2(int u, int v) {  
  26.     edge2[++top2] = (E) {v, head2[u]};  
  27.     head2[u] = top2;  
  28. }  
  29. int low[maxn], dfn[maxn], timer, c[maxn], cnt, sta[maxn], stp;  
  30. bool ins[maxn];  
  31. int val[maxn];  
  32. void tarjan(int u) {  
  33.     low[u] = dfn[u] = ++ timer;  
  34.     sta[++stp] = u, ins[u] = true;  
  35.     for (int i = head[u]; i; i = edge[i].nxt) {  
  36.         int v = edge[i].to;  
  37.         if (!dfn[v]) {  
  38.             tarjan(v);  
  39.             low[u] = min(low[u], low[v]);  
  40.         } else if (ins[v])  
  41.             low[u] = min(low[u], dfn[v]);  
  42.     }  
  43.     if (dfn[u] == low[u]) {  
  44.         ++cnt;  
  45.         int x;  
  46.         do {  
  47.             x = sta[stp--];  
  48.             ins[x] = false;  
  49.             c[x] = cnt;  
  50.             val[cnt] = max(val[cnt], x);  
  51.         } while (x != u);  
  52.     }  
  53. }  
  54. int ind[maxn];  
  55. void build() {  
  56.     for (int u = 1; u <= n; ++u)  
  57.         for (int i = head[u]; i; i = edge[i].nxt) {  
  58.             int v = edge[i].to;  
  59.             if (c[u] != c[v])  
  60.                 insert2(c[u], c[v]), ++ind[c[v]];  
  61.         }  
  62. }  
  63. void dp() {  
  64.     queue<int> que;  
  65.     for (int i = 1; i <= cnt; ++i)  
  66.         if (!ind[i]) que.push(i);  
  67.     while (!que.empty()) {  
  68.         int u = que.front(); que.pop();  
  69.         for (int i = head2[u]; i; i = edge2[i].nxt) {  
  70.             int v = edge2[i].to;  
  71.             val[v] = max(val[v], val[u]);  
  72.             --ind[v];  
  73.             if (!ind[v])  
  74.                 que.push(v);  
  75.         }  
  76.     }  
  77.     return;  
  78. }  
  79. int main() {  
  80.     read(n), read(m);  
  81.     int u, v;  
  82.     for (int i = 1; i <= m; ++i) {  
  83.         read(u), read(v);  
  84.         insert(v, u);  
  85.     }  
  86.     for (int i = 1; i <= n; ++i)  
  87.         if (!dfn[i])  
  88.             tarjan(i);  
  89.     build();  
  90.     dp();  
  91.     for (int i = 1; i <= n; ++i)  
  92.         printf("%d ", val[c[i]]);  
  93.     return 0;  
  94. }  

至此luogu上真哥留下的缩点习题全部完成。晚上更新对最小树形图(朱刘算法)的理解。

猜你喜欢

转载自www.cnblogs.com/TY02/p/11119893.html
今日推荐