手抄代码 + 学习指针 + 冥思苦想一晚上终于——在一瞬间开窍了。果然题目都是这样:突破了一个点,一切都是柳暗花明。

  题面描述:

  样例:

  这道题目,首先注意到给定的边的性质:这些边在平面上构成了一棵树,区间之间互不相交,只有包含与外离两种关系。如果不考虑颜色的限制,我们将原图的边权转化为网络流中的流量,那么原图中的最短路就转化为了新图中的最小割。那么在张网络流的图上,我们应当如何限制颜色的制约关系呢?

  首先一个明显的思路:这张图是一个树形的结构,画在一个类似数轴的东西上面会很容易发现最下面的一条链上的点是无论如何都要经过的;而不存在于这条链上的点,则一定不会被访问到,其所代表的颜色也一定不会被我们所选择。对于这样的点,我们将它们从我们的图上删去。最小割:将图中的点分做S割与T割的两个部分。我们对于每一个颜色都做出一个辅助点,若这个点位于S割,代表这个颜色被选择;位于T割,代表不被选择。

  我们将所有的边画成树后,从所有的大区间层层推进的向其所包含的小区间连边(类似线段树)。注意在这里我们先忽略那些链接相邻两点的区间不作处理。一个显然的性质:一个大区间所跳过的点,一定包含了所有它包含的小区间跳过的点。那么我们就从区间往它跳过的颜色的点连上INF的边(如果大区间&小区间共同跳过了一个颜色,这条边从小区间->颜色)。注意之前我们确定一定不会经过的颜色,从它向T点连INF的边,保证它一定处于T割。

  这样我们可以发现:如果不选择这一个点,说明我们的割线一定在这个颜色的点的上方->我们选择了所有跳过这个颜色的区间。如果选择一个点,说明我们的割线在这个点的下方->我们没有选择任何一个跳过这个颜色的区间。这样,限制就得以满足了。最后,那些链接相邻两点的边:如果包含于大区间,则由这些区间其中最小的一个向T点连边权值的流量的边,否则就从S连向T,流量也为边权值。

  感觉读懂了之后除了感叹还是感叹——我学过网络流吗?不存在的。【摊手】

#include <bits/stdc++.h>
using namespace std;
#define maxn 10000
#define INF 99999
#define pb push_back
#define vec vector
int n, m, cnp, cnt, s, t;
int Map[maxn][maxn], lev[maxn], nxt[maxn];
int ans, a[maxn], id[maxn];
bool tag[maxn], mark[maxn], flag[maxn];
vector <int> u, v, w, c;
queue <int> q; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} struct node
{
int u, v, w; bool flag;
bool operator <(node t)
{ return v - u < t.v - t.u; } // 区间长度短的放在前面
}E[maxn]; struct edge
{
int v, f;
edge *nxt, *rev;
}e[], *p = e, *head[maxn], *cur[maxn]; void add(int u, int v, int f1, int f2)
{
*p = (edge) { v, f1, head[u], p + }, head[u] = p ++;
*p = (edge) { u, f2, head[v], p - }, head[v] = p ++;
} bool bfs()
{
memset(lev, , sizeof(lev));
q.push(s); lev[s] = ;
while(!q.empty())
{
int u = q.front(); q.pop();
for(edge *i = head[u]; i; i = i -> nxt)
{
if(!lev[i -> v] && i -> f)
{
lev[i -> v] = lev[u] + ;
q.push(i -> v);
}
}
}
return lev[t];
} int dfs(int x, int nf)
{
int ff = ;
if(x == t) return nf;
for(edge *i = cur[x]; i; i = i -> nxt)
{
if(!nf) break;
if(i -> f && lev[i -> v] == lev[x] + )
{
int af = dfs(i -> v, min(nf, i -> f));
i -> f -= af, i -> rev -> f += af, cur[x] = i;
ff += af, nf -= af;
}
}
cur[x] = head[x];
return ff;
} int Work(vec <int> u, vec <int> v, vec <int> w, vec <int> c)
{
memset(Map, , sizeof(Map));
for(int i = ; i < (int) u.size(); i ++)
Map[u[i]][v[i]] = Map[v[i]][u[i]] = min(Map[u[i]][v[i]], w[i]);
flag[n] = ;
for(int i = n - ; i; i --)
for(int j = i + ; j <= n; j ++)
flag[i] |= flag[j] && Map[i][j] < << ;
for(int i = ; i <= n; i = nxt[i])
{
a[id[i] = ++ cnt] = i; nxt[i] = n + ;
for(int j = i + ; j <= n; j ++)
if(Map[i][j] < << && nxt[i] > n && flag[j])
{ nxt[i] = j; break; }
for(int j = ; j < i; j ++)
if(Map[i][j] < << && id[j] && id[j] != cnt - )
E[++ cnp] = (node) { id[j], cnt, Map[i][j], };
}
if(a[cnt] != n) return -;
E[++ cnp] = (node) { id[], id[n], , };
sort(E + , E + cnp);
s = cnp, t = cnp + ;
for(int i = ; i <= n - ; i ++)
if(!id[i]) add(cnp + c[i - ], t, << , << );
for(int i = ; i <= cnp; i ++)
{
for(int j = ; j < i; j ++)
if(!E[j].flag && E[i].u <= E[j].u && E[i].v >= E[j].v)
E[j].flag = , add(i, j, E[j].w, << );
for(int j = E[i].u + ; j < E[i].v; j ++)
if(!tag[j]) tag[j] = , add(i, cnp + c[a[j] - ], << , << );
for(int j = E[i].u; j < E[i].v; j ++)
if(!mark[j]) mark[j] = , add(i, t, Map[a[j]][a[j + ]], );
}
for(int i = ; i <= t; i ++) cur[i] = head[i];
while(bfs()) if((ans += dfs(s, << )) >= INF) return -;
return ans;
} int main()
{
n = read(), m = read();
for(int i = ; i <= n - ; i ++)
{
int x = read();
c.pb(x);
}
for(int i = ; i <= m; i ++)
{
int x = read(), y = read(), z = read();
u.pb(x), v.pb(y), w.pb(z);
}
printf("%d\n", Work(u, v, w, c));
return ;
}

【考试记录】4.8 Path (网络流 —— 劲题)的更多相关文章

  1. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  2. 【网络流24题】最长k可重区间集(费用流)

    [网络流24题]最长k可重区间集(费用流) 题面 Cogs Loj 洛谷 题解 首先注意一下 这道题目里面 在Cogs上直接做就行了 洛谷和Loj上需要判断数据合法,如果\(l>r\)就要交换\ ...

  3. LibreOJ #6014. 「网络流 24 题」最长 k 可重区间集

    #6014. 「网络流 24 题」最长 k 可重区间集 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   ...

  4. Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流)

    Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流) Description G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使n ...

  5. Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)

    Libre 6012 「网络流 24 题」分配问题 (网络流,费用流) Description 有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为\(c_{ij}\).试设计一个将n件工作分 ...

  6. Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流)

    Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流) Description W 公司有m个仓库和n个零售商店.第i个仓库有\(a_i\)个单位的货物:第j个零售商店需要\( ...

  7. LibreOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题

    #6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  8. LIbreOJ #6011. 「网络流 24 题」运输问题 最小费用最大流

    #6011. 「网络流 24 题」运输问题 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

  9. LibreOJ #6008. 「网络流 24 题」餐巾计划 最小费用最大流 建图

    #6008. 「网络流 24 题」餐巾计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据   题目描述 ...

随机推荐

  1. 【ospf-路由过滤】

  2. Leecode刷题之旅-C语言/python-26.移除元素

    /* * @lc app=leetcode.cn id=27 lang=c * * [27] 移除元素 * * https://leetcode-cn.com/problems/remove-elem ...

  3. C语言实例解析精粹学习笔记——42(插入排序)

    实例说明: 将一个整数数组按从小到大的顺序进行排序.(主要学习基本的插入排序和改进的冒泡排序的算法和应用) 思路1: 从第一个数据开始,分别比较其后的数据,若比它小,则将这两个数的位置交换:从第一个数 ...

  4. 10---git安装

    卸载原来的版本: # 查看版本 git --version # 移除原来的版本 yum remove git 安装依赖库: yum install curl-devel expat-devel get ...

  5. Python爬虫之JS异步加载

    一.判断异步加载方式(常用的JS库) 1. jQuery(70%) # 搜索 jquery 茅塞顿开 <script src="http://ajax.googleapis.com/a ...

  6. Grok Debugger本地安装(转载)

    原文链接:http://fengwan.blog.51cto.com/508652/1758845 最近在使用ELK对日志进行集中管理,因为涉及到日志的规则经常要用到http://grokdebug. ...

  7. 【TRICK】[0,n)中所有大小为k的子集的方法

    << k) - ; <<n)) { int x = comb & -comb, y = comb + x; comb = (((comb & ~y)/x)> ...

  8. springmvc 处理put,delete请求

    前言:ajax用post编辑,删除提示越权操作状态为500,修改半晌最后大神指点说是:type修改为post和delete模式 最后还是一知半解,但是程序却正常使用了.当然注意我用的mvc,contr ...

  9. shell -- for、while用法

    #数字段形式for i in {1..10}do   echo $idone #详细列出(字符且项数不多)for File in 1 2 3 4 5do    echo $Filedone #对存在的 ...

  10. Python连接符的种类和使用区别

    python的连接符主要有 加号(+).逗号(,).空格(   ) .反斜线(\).join()的方式. 加号(+),demo如下: #注意,+只能连接字符串,如果一个是字符串一个是数字就会报错 pr ...