Codeforces Gym 101190M Mole Tunnels - 费用流

题目传送门

  传送门

题目大意

  $m$只鼹鼠有$n$个巢穴,$n - 1$条长度为$1$的通道将它们连通且第$i(i > 1)$个巢穴与第$\left\lfloor \frac{i}{2}\right\rfloor$个巢穴连通。第$i$个巢穴在最终时允许$c_i$只醒来的鼹鼠最终停留在这。已知第$i$只鼹鼠在第$p_i$个巢穴睡觉。要求求出对于每个满足$1 \leqslant k \leqslant n$的$k$,如果前$k$只鼹鼠醒来,最小的移动距离的总和。

  考虑费用流的建图和暴力做法,把原图的边容量设为无限大,费用设为1(每条无向边要拆成两条),每个点再向汇点连一条边,容量为$c_i$,费用为0。

  对于每次源点向$p_i$增广1单位的流量。

  显然这样会超时,考虑优化费用流。

  显然有:

  • 每次增广的路径一定是一条简单路径
  • 对于原图的一条无向边,它两个方向的边不会同时有流量(走另外一条弧的反向弧显然可以减少费用)

  那么每次枚举路径的LCA,对于每个点记录一下$f_i$表示从$i$走到子树内的任意一个点的最短距离。

  显然每次更新边权后很容易能够维护$f$。时间复杂度$O(n\log n)$。

Code

  1 /**
  2  * Codeforces
  3  * Gym#101190M
  4  * Accepted
  5  * Time: 108ms
  6  * Memory: 2200k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11 #ifndef WIN32
 12 #define Auto "%lld"
 13 #else
 14 #define Auto "%I64d"
 15 #endif
 16 using namespace std;
 17 typedef bool boolean;
 18
 19 #define ll long long
 20
 21 const signed ll llf = (signed ll) (~0ull >> 3);
 22 const signed int inf = (signed) (~0u >> 2);
 23 const int N = 131072;
 24
 25 #define pii pair<int, int>
 26
 27 pii operator + (pii a, int b) {
 28     return pii(a.first + b, a.second);
 29 }
 30
 31 int n, m;
 32 int w[N], c[N];
 33 pii fd[N];
 34
 35 inline void init() {
 36     scanf("%d%d", &n, &m);
 37     for (int i = 1; i <= n; i++) {
 38         scanf("%d", c + i);
 39     }
 40 }
 41
 42 int value(int p, int dir) { // up : +1, down : -1
 43     int prod = w[p] * dir;
 44     return (prod >= 0) ? (1) : (-1);
 45 }
 46
 47 void __update(int p) {
 48     fd[p] = pii(inf * (!c[p]), p);
 49     if ((p << 1) <= n && fd[p << 1].first != inf)
 50         fd[p] = min(fd[p], fd[p << 1] + value(p << 1, -1));
 51     if ((p << 1) < n && fd[p << 1 | 1].first != inf)
 52         fd[p] = min(fd[p], fd[p << 1 | 1] + value(p << 1 | 1, -1));
 53 }
 54
 55 int update(int s) {
 56     int val = fd[s].first, g = s, v = fd[s].second, len = 0;
 57     for (int p = s, d = (p & 1), q, cmp; len += value(p, 1), p >>= 1; d = p & 1) {
 58         q = p << 1 | (d ^ 1);
 59         if (q <= n && (cmp = fd[q].first + value(q, -1) + len) < val)
 60             val = cmp, g = p, v = fd[q].second;
 61         if (c[p] && len < val)
 62             val = len, g = v = p;
 63     }
 64     c[v]--;
 65     for (int p = s; p != g; p >>= 1) {
 66         w[p]++;
 67         __update(p);
 68     }
 69     for (int p = v; p != g; p >>= 1) {
 70         w[p]--;
 71         __update(p);
 72     }
 73     for (int p = g; p; p >>= 1)
 74         __update(p);
 75 //    cerr << s << " " << v << ‘\n‘;
 76     return val;
 77 }
 78
 79 inline void solve() {
 80     for (int i = 1; i <= n; i++)
 81         fd[i] = pii(inf * (!c[i]), i);
 82     for (int i = n; i > 1; i--)
 83         fd[i >> 1] = min(fd[i >> 1], fd[i] + 1);
 84
 85     int x;
 86     ll res = 0;
 87     while (m--) {
 88         scanf("%d", &x);
 89         res += update(x);
 90         printf(Auto" ", res);
 91     }
 92 }
 93
 94 int main() {
 95     freopen("mole.in", "r", stdin);
 96     freopen("mole.out", "w", stdout);
 97     init();
 98     solve();
 99     return 0;
100 }

原文地址:https://www.cnblogs.com/yyf0309/p/10193274.html

时间: 2024-07-30 13:05:33

Codeforces Gym 101190M Mole Tunnels - 费用流的相关文章

Codeforces 362E Petya and Pipes 费用流建图

题意: 给一个网络中某些边增加容量,增加的总和最大为K,使得最大流最大. 费用流:在某条边增加单位流量的费用. 那么就可以2个点之间建2条边,第一条给定边(u,v,x,0)这条边费用为0 同时另一条边(u,v,K,1)费用为1,那么就可以通过限制在增广时相应的费用即可找出最大流 个人觉得这样做的原因是每次增光都是最优的.所以通过限制最终费用不超过K可以得到最优解 #include <map> #include <set> #include <list> #include

Codeforces Gym 100203I I WIN 最大流

原题链接:http://codeforces.com/gym/100203/attachments/download/1702/statements.pdf 题解 首先寻找每个I,然后枚举形状,如果匹配的话,就将源点连一条边到当前匹配的W,再从W连条边到I,I需要拆点,然后将拆点后面的那个点连接到N,从N连接到汇点.所有边的容量都是1.需要注意避免产生重边.然后最大流就是答案. 代码 #include<iostream> #include<stack> #include<ve

Codeforces Gym 100002 E &quot;Evacuation Plan&quot; 费用流

"Evacuation Plan" Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100002 Description The City has a number of municipal buildings and a number of fallout shelters that were build specially to hide municipal workers in case 

【BZOJ4849】[Neerc2016]Mole Tunnels 模拟费用流

[BZOJ4849][Neerc2016]Mole Tunnels Description 鼹鼠们在底下开凿了n个洞,由n-1条隧道连接,对于任意的i>1,第i个洞都会和第i/2(取下整)个洞间有一条隧道,第i个洞内还有ci个食物能供最多ci只鼹鼠吃.一共有m只鼹鼠,第i只鼹鼠住在第pi个洞内,一天早晨,前k只鼹鼠醒来了,而后n-k只鼹鼠均在睡觉,前k只鼹鼠就开始觅食,最终他们都会到达某一个洞,使得所有洞的ci均大于等于该洞内醒着的鼹鼠个数,而且要求鼹鼠行动路径总长度最小.现对于所有的1<=k

【网络流24题】No.19 负载平衡问题 (费用流)

[题意] G 公司有 n 个沿铁路运输线环形排列的仓库, 每个仓库存储的货物数量不等. 如何用最少搬运量可以使 n 个仓库的库存数量相同.搬运货物时,只能在相邻的仓库之间搬运. 输入文件示例input.txt517 9 14 16 4 输出文件示例output.txt11 [分析] 其实我觉得这题可以贪心啊..n^2贪心??.没细想.. 打的是费用流.. 大概这样建图: 懒得写了..凌乱之美.. 求满流费用.. 1 #include<cstdio> 2 #include<cstdlib&

POJ 3422 kaka&#39;s matrix trvals(费用流)

#include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #include <vector> #include <queue> #include <stack> #include <set> #include <map> #include <cma

hdu 2448 Mining Station on the Sea【网络费用流】

Mining Station on the Sea Time Limit: 5000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2371    Accepted Submission(s): 732 Problem Description The ocean is a treasure house of resources and the development

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一

POJ 2135 Farm Tour &amp;&amp; HDU 2686 Matrix &amp;&amp; HDU 3376 Matrix Again 费用流求来回最短路

累了就要写题解,最近总是被虐到没脾气. 来回最短路问题貌似也可以用DP来搞,不过拿费用流还是很方便的. 可以转化成求满流为2 的最小花费.一般做法为拆点,对于 i 拆为2*i 和 2*i+1,然后连一条流量为1(花费根据题意来定) 的边来控制每个点只能通过一次. 额外添加source和sink来控制满流为2. 代码都雷同,以HDU3376为例. #include <algorithm> #include <iostream> #include <cstring> #in