首页 > 其他分享 >P5029 T'ill It's Over

P5029 T'ill It's Over

时间:2023-08-05 16:33:18浏览次数:56  
标签:std solver int ill P5029 add Over inf top

一个序列 \(d\{n\} = \{1\}\),有 \(m\) 种操作,每种操作都有一个操作次数的最大限制,且可以分为 \(4\) 类:
1. 将任意一个满足 \(d_i = a\) 的 \(d_i\) 改为 \(b\);
2. 将任意一个满足 \(d_i \in [a1, a2]\) 的 \(d_i\) 改为 \(b\);
3. 将任意一个满足 \(d_i = a\) 的 \(d_i\) 改为 \([b1, b2]\) 中的一个数;
4. 将任意一个满足 \(d_i \in [a1, a2]\) 的 \(d_i\) 改为 \([b1, b2]\) 中的一个数。
求最后序列中最多有多少个值为 \(k\) 的数。
\(n \le 10^7, k \le 2 \times 10^4, m \le 10^5\)。

不难看出这是一道网络流的题目,我们先考虑暴力。记源汇点分别为 \(s, t\),对于题目的每一种限制,我们直接暴力连边,容量为对应的限制,再连边 \((s, 1, n)\) 与 \((k, t, n)\),求从 \(s\) 到 \(t\) 的最大流即可。

真的是这样吗?其实不是,观察可以发现,题目要求的是总的次数不超过限制,而如果直接连边则是对于每一对 \(a, b\) 均不超过限制,而这是不对的,还有可能有多的但是题目数据太水了,这一点好像没有怎么体现。因此,对于每一个操作都应该新建两个虚拟节点 \(l\) 与 \(r\),对于所有的 \(a\),连边 \((a, l, \inf)\),对于所有的 \(b\),连边 \((r, b, \inf)\),再连边 \((l, r, lim)\) 即可,其中 \(lim\) 为这种操作的限制次数。这样总体的点数为 \(\mathcal{O}(k)\) 的,而总边数达到了惊人的 \(\mathcal{O}(mk ^ 2)\),这显然是不行的。

观察到题目给出的形式是点向点连边、区间向区间连边、点与区间互相连边,非常符合线段树优化建图的形式,于是我们直接套一个线段树优化建图的板子,就可以将点数与边数均优化至 \(\mathcal{O}(k \log k)\) 级别。

具体在实现时,我们队线段树上的每一个区间都赋予一个标号,然后在连边时,通过在线段树上 DFS,找出所有有用的区间标号并将其存储至一个栈里,然后再连边即可。

#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 1e5 + 50, inf = 0x3f3f3f3f, M = 1e6 + 50;
int n, m, k, cnt;
template<int N = 1000050, int M = 3000050>
struct Dinic {
  static const int inf = 0x3f3f3f3f;
  struct Edge {
    int u, v, cap, flow;
    Edge() = default;
    Edge(int _u, int _v, int _c) { u = _u, v = _v, cap = _c, flow = 0; }
  } edges[M];
  int cnt = 0;
  std::vector<int> adj[N];
  int s, t, dis[N], cur[N];
  void add(int u, int v, int cap) {
    edges[cnt++] = Edge(u, v, cap), edges[cnt++] = Edge(v, u, 0);
    adj[u].push_back(cnt - 2), adj[v].push_back(cnt - 1);
  }
  bool bfs() {
    std::memset(cur, 0, sizeof(cur));
    std::memset(dis, 0x3f, sizeof(dis));
    std::queue<int> q;
    q.push(s), dis[s] = 0;
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      for (auto i : adj[u]) {
        auto [_, v, cap, flow] = edges[i];
        if (dis[v] == inf && cap > flow) dis[v] = dis[u] + 1, q.push(v);
      }
    }
    return dis[t] != inf;
  }
  int dfs(int u, int lim) {
    if (u == t || !lim) return lim;
    int res = 0;
    for (int &i = cur[u], f; i < adj[u].size(); i++) {
      auto &[_, v, cap, flow] = edges[adj[u][i]];
      if (dis[v] == dis[u] + 1 && (f = dfs(v, std::min(lim, cap - flow)))) {
        res += f, lim -= f;
        flow += f, edges[adj[u][i] ^ 1].flow -= f;
        if (!lim) break;
      }
    }
    return res;
  }
  int maxFlow(int _s, int _t) {
    int res = 0;
    s = _s, t = _t;
    while (bfs()) res += dfs(s, inf);
    return res;
  }
};
Dinic solver;
int idx[M], rev[M];
void build(int s, int t, int u) {
  idx[u] = ++cnt, rev[u] = ++cnt;
  if (s == t) {
    solver.add(idx[u], rev[u], inf), solver.add(rev[u], idx[u], inf);
    return;
  }
  int mid = (s + t) >> 1, lc = u << 1, rc = u << 1 | 1;
  build(s, mid, lc), build(mid + 1, t, rc);
  solver.add(idx[u], idx[lc], inf), solver.add(idx[u], idx[rc], inf);
  solver.add(rev[lc], rev[u], inf), solver.add(rev[rc], rev[u], inf);
}
int st[N], top;
void find(int l, int r, int s, int t, int u) {
  if (l <= s && t <= r) {
    st[++top] = u;
    return;
  }
  int mid = (s + t) >> 1, lc = u << 1, rc = u << 1 | 1;
  if (mid >= l) find(l, r, s, mid, lc);
  if (mid <  r) find(l, r, mid + 1, t, rc);
}
signed main() {
  std::ios::sync_with_stdio(false);
  std::cin.tie(nullptr);
  std::cin >> n >> m >> k;
  build(1, k, 1);
  for (int i = 1; i <= m; i++) {
    int opt, lim;
    std::cin >> opt >> lim;
    int ts = ++cnt, tt = ++cnt;
    solver.add(ts, tt, lim);
    if (opt == 1) {
      int a, b;
      std::cin >> a >> b;
      find(a, a, 1, k, 1);
      while (top) solver.add(rev[st[top--]], ts, inf);
      find(b, b, 1, k, 1);
      while (top) solver.add(tt, idx[st[top--]], inf);
    } else if (opt == 2) {
      int a1, a2, b;
      std::cin >> a1 >> a2 >> b;
      find(a1, a2, 1, k, 1);
      while (top) solver.add(rev[st[top--]], ts, inf);
      find(b, b, 1, k, 1);
      while (top) solver.add(tt, idx[st[top--]], inf);
    } else if (opt == 3) {
      int a, b1, b2;
      std::cin >> a >> b1 >> b2;
      find(a, a, 1, k, 1);
      while (top) solver.add(rev[st[top--]], ts, inf);
      find(b1, b2, 1, k, 1);
      while (top) solver.add(tt, idx[st[top--]], inf);
    } else {
      int a1, a2, b1, b2;
      std::cin >> a1 >> a2 >> b1 >> b2;
      find(a1, a2, 1, k, 1);
      while (top) solver.add(rev[st[top--]], ts, inf);
      find(b1, b2, 1, k, 1);
      while (top) solver.add(tt, idx[st[top--]], inf);
    }
  }
  int s = ++cnt, t = ++cnt;
  find(1, 1, 1, k, 1);
  int p1 = st[top];
  top = 0;
  find(k, k, 1, k, 1);
  int pk = st[top];
  top = 0;
  solver.add(s, rev[p1], n), solver.add(idx[pk], t, n);
  std::cout << solver.maxFlow(s, t) << "\n";
  return 0;
}

标签:std,solver,int,ill,P5029,add,Over,inf,top
From: https://www.cnblogs.com/forgot-dream/p/17608132.html

相关文章

  • 机器学习中模型泛化能力和过拟合现象(overfitting)的矛盾、以及其主要缓解方法正则化
    机器学习中模型泛化能力和过拟合现象(overfitting)的矛盾、以及其主要缓解方法正则化技术原理初探1.从多项式曲线拟合中的过拟合问题说起我们以一个简单的回归问题开始,说明许多关键的概念。假设我们观察到一个实值输入变量x,我们想使用这个观察来预测实值......
  • OOMKilled
    问题描述:某应用节点频繁重启通过describe查看详情发现 kubectl-n<yournamespace>describepod<yourapplicationpodid> Command:javaArgs:-Denv=PRO-XX:+UnlockExperimentalVMOptions-XX:+UseCGroupMemoryLimitForHeap-......
  • Illustrator软件-Illustrator下载-中文简体版 软件推荐
    Ai2020功能介绍1、自由渐变全新的混色功能可让您创建更丰富、逼真的渐变,从而呈现出更自然的效果。2、全局编辑可同时修改多个画板中的类似对象,以节省时间。3、直观地浏览字体现在您可以更加轻松地浏览不同的字体类别,更快地找到合适的字体。现在您还可以选择不同的示例文本选项。4......
  • ai软件-Illustrator下载-中文简体版使用 软件推荐
    Ai2020官方版是一款由Adobe公司推出的矢量图形制作软件。Ai2020最新版软件拥有强大的图像处理功能,用户能够轻松的进行布局和组织,创建出色的矢量图稿。AdobeIllustrator2020软件拥有更自然、更丰富逼真的渐变效果,并增强了文件读取机制,适合广告设计、插画回执、海报书籍等方面使......
  • 12-面向对象-方法重载(OverLoad)
    基本介绍重载(Overload):指一个类中可以有多个方法具有相同的名字,但这些方法的参数不同(参数的类型和个数不同)即在Java中允许同一个类中,多个同名方法的存在,但要求形参列表不一致!publicclassOverLoad01{publicstaticvoidmain(String[]args){MyCalculatormc......
  • Linux:user is not in the sudoers file. This incident will be reported 解决方法
    学习自:userisnotinthesudoersfile.Thisincidentwillbereported解决方法_一路奔跑94的博客-CSDN博客1、原因没有在权限文件中说明该用户具有sudo权限2、解决步骤1)以root身份去/etc/sudoers文件中,编辑vi/etc/sudoers2)在rootALL=(ALL)ALL之下添加一行xxxALL......
  • gitlab 报错error: 20667 bytes of body are still expectedB fatal: early EOF
    报错如下:C:\Users\meiktv\StudioProjects\meiktv_android_vod_3>gitclonehttps://gitlab.meiktv.com/client/meiktv_android_vod.gitCloninginto'meiktv_android_vod'...remote:Enumeratingobjects:46631,done.remote:Countingobjects:100%(26......
  • ThinkPad -- 升级至 Vista 前需要先卸载Rescue and Recovery
    http://www.91bjb.com/bbs/redirect.php?fid=30&tid=39791&goto=nextoldsetX61/T61/X200/T400/T500/W500/W700使用XP安装盘安装系统及驱动全攻略(视频)ThinkPad--升级至Vista前需要先卸载RescueandRecoveryThinkPad--升级至Vista故障现象较旧版本的RescueandRe......
  • 如何与 Dillard's 建立 EDI 连接?
    Dillard's是主营时装、化妆品和家居用品的零售商,为顾客提供高质量的商品和优质的购物体验。2022年,Dillard's公司位列当年《财富》美国500强排行榜第488名。本文将为大家介绍Dillard's的EDI需求,了解如何快速对接Dillard'sEDI。Dillard'sEDI需求分析报文标准:X12......
  • Essential diagnostic tools: cat caterpillar et diagnostic tool
    Essentialdiagnostictools:catcaterpillaretdiagnostictoolIntoday'sfast-pacedworld,theimportanceofefficientandaccuratediagnostictoolscannotbeoverstated.Whetheryouareamechanic,technician,orautomobileenthusiast,havingaccess......