专栏文章

题解:P5008 [yLOI2018] 锦鲤抄

P5008题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@min4en56
此快照首次捕获于
2025/12/01 20:23
3 个月前
此快照最后确认于
2025/12/01 20:23
3 个月前
查看原文

题意

题意简化版说的很清楚了。

分析

我们先贪心的思考,在选点时一定是优先选权值大的。然后我们再考虑哪些点能选。
先把图缩点变成一个 DAG 然后,我们发现所有入度不为 00 的强连通分量的所有点都是可选点,反之则其中必须有一个点作为火源,也就是必须留一个点不选,所以尽量贪权值最小的不选。
看数据范围时,我们发现题目不保证没有自环,还是个善良题面,于是我们思考自环会导致什么。容易发现,如果一个强连通分量中不选的点有自环,则其可以被选。
综上,把满足条件的点挑出来,排个序,取前 kk 个,累加然后输出,即可切掉本题。
CPP
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5 + 10, K = 20, mod = 1e9 + 7;
int n, m, f[N], dfn[N], ar, a[N], low[N], ins[N], scc[N], col, cnti[N], en[N];
vector <int> edge[N], blg[N];
stack <int> st;
int chkmn(int &a, const int &b) {return a = min(a, b);}
void tarjan(int p)
{
  dfn[p] = low[p] = ++ ar;
  st.push(p); ins[p] = 1;
  for (auto to : edge[p])
  {
    if (!dfn[to])
    {
      tarjan(to);
      chkmn(low[p], low[to]);
    }
    else if (ins[to])
      chkmn(low[p], dfn[to]);
  }
  if (low[p] == dfn[p])
  {
    col ++;
    while (!st.empty())
    {
      int t = st.top(); st.pop();
      ins[t] = 0;
      scc[t] = col;
      blg[col].emplace_back(t);
      if (t == p)
        break;
    }
  }
}
signed main() {
  cin.tie(0)->sync_with_stdio(0);
  int k;
  cin >> n >> m >> k;
  for (int i = 1; i <= n; i ++) cin >> a[i];
  while (m --)
  {
    int u, v;
    cin >> u >> v;
    edge[u].push_back(v);
  }
  for (int i = 1; i <= n; i ++) if (!dfn[i]) tarjan(i);
  for (int i = 1; i <= n; i ++){
    for (auto to : edge[i])
    {
      if (scc[to] != scc[i]) cnti[scc[to]] ++;
      if (to == i) en[scc[i]] = 1;
    }
  }
  auto cmp = [](int x, int y){return a[x] > a[y];};
  vector <int> p;
  for (int i = 1; i <= col; i ++)
  {
    if (en[i] || cnti[i]) for (auto it : blg[i]) p.emplace_back(a[it]);
    else
    {
      sort(blg[i].begin(), blg[i].end(), cmp);
      for (int j = 0; j < blg[i].size() - 1; j ++) p.emplace_back(a[blg[i][j]]);
    }
  }
  int ans = 0;
  if (k > p.size()) k = p.size();
  nth_element(p.begin(), p.begin() + k, p.end(), greater<int>());
  for (int i = 0; i < k; i ++)  ans += p[i];//;, cout << p[i] << " ";
  // cout << endl;
  cout << ans << endl;
  return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...