传送门

直接搞很复杂,考虑转化问题

题目只要求第1个人最多能获得的物品数量

所以如果一种物品拥有多个和一个是没区别的

那么考虑每种物品对第1个人怎样贡献

显然要经过一些交换最终到达第一个人那里

发现很像一个流,那么考虑建立网络流模型

建一个源点向每个点连一条最大流量为1的边,相当于初始每个点有1个物品

点1向汇点连一条 $a_1$ 的边,因为点1最多能放 $a_1$ 个物品

因为一个点 i 同时最多只能有 $a_i$ 种物品,所以也把其他个点拆成两个,之间连一条流量为 $a_i$ 的边

考虑点与点之间的连接

因为交换是按时间顺序的,所以不可能直接连

同样拆点

把一个点 i 分成 m 个点,表示 i 在 1~m 的时间点上的状态,显然这 m 个点之间的流量为 $a_i$(一个点 i 最多同时有 $a_i$ 种不同的物品)

这样就可以把不同的点连起来了

具体说来就是:如果在时间 i , a 和 b 发生了交换,那么在 a 拆出来的第 i 个点和 b 拆出来的第 i 个点之间连双向边

显然边权均为 1 (一次只能换一个物品)

可以参照下面的丑图:

但是这样有$nm$个点,显然不行

但是可以发现只有向其他点连接的点是有用的,即一串 m 个点只有向外面其他点有连接的点是有用的,所以我们动态地加点连边,只有对于需要的点我们才要连边

这样因为边数是 m 所以要加的点数就是 2m

要注意一些细节

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') {if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=3e5+,INF=1e9+;
int fir[N],from[N<<],to[N<<],val[N<<],cntt=,Fir[N];
inline void add(int a,int b,int c)
{
from[++cntt]=fir[a]; fir[a]=cntt;
to[cntt]=b; val[cntt]=c;
from[++cntt]=fir[b]; fir[b]=cntt;
to[cntt]=a; val[cntt]=;
}
queue <int> q;
int n,m,tot,ans;
int S,T,p[N],pre[N],dep[N];
//p是每个点的容量,pre[i]是为了动态加点,存点i的上个时间的点的编号
//以下为Dinic
bool BFS()
{
memset(dep,,sizeof(dep));
q.push(S); dep[S]=; int x;
while(!q.empty())
{
x=q.front(); q.pop();
for(int i=fir[x];i;i=from[i])
{
int &v=to[i]; if(dep[v]||!val[i]) continue;
dep[v]=dep[x]+; q.push(v);
}
}
for(int i=;i<=tot;i++) Fir[i]=fir[i];
return dep[T] ? : ;
}
int DFS(int x,int mif)
{
if(!mif||x==T) return mif;
int fl=,res=;
for(int i=Fir[x];i;i=from[i])
{
Fir[x]=i; int &v=to[i]; if(dep[v]!=dep[x]+) continue;
if( res=DFS(v, min(mif,val[i]) ) )
{
fl+=res; mif-=res;
val[i]-=res; val[i^]+=res;
if(!mif) break;
}
}
return fl;
}
//以上为Dinic
void slove()//处理读入
{
int a,b; ans=tot=; cntt=;//多组数据记得初始化
memset(fir,,sizeof(fir));
n=read(); m=read();
S=++tot; T=++tot;//建源点和汇点
for(int i=;i<=n;i++)
{
add(S,pre[i]=++tot,);//源点向每个初始点连边
p[i]=read();
}
while(m--)
{
a=read(); b=read();
int na=++tot,nb=++tot;//新的时间的点
add(pre[a],na,p[a]); add(pre[b],nb,p[b]);//和上一时间的点相连
add(na,nb,); add(nb,na,);//之间连双向边
pre[a]=na; pre[b]=nb;//更新pre
}
add(pre[],T,p[]);//最后点1连向汇点,容量为p[1]
while(BFS()) ans+=DFS(S,INF);
printf("%d\n",ans);
}
int main()
{
//freopen("collection.in","r",stdin);
//freopen("collection.out","w",stdout);
int T=read();
while(T--) slove();
return ;
}

BZOJ 5421: 收藏家的更多相关文章

  1. BZOJ 2127: happiness [最小割]

    2127: happiness Time Limit: 51 Sec  Memory Limit: 259 MBSubmit: 1815  Solved: 878[Submit][Status][Di ...

  2. BZOJ 3275: Number

    3275: Number Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 874  Solved: 371[Submit][Status][Discus ...

  3. BZOJ 2879: [Noi2012]美食节

    2879: [Noi2012]美食节 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 1834  Solved: 969[Submit][Status] ...

  4. bzoj 4610 Ceiling Functi

    bzoj 4610 Ceiling Functi Description bzoj上的描述有问题 给出\(n\)个长度为\(k\)的数列,将每个数列构成一个二叉搜索树,问有多少颗形态不同的树. Inp ...

  5. BZOJ 题目整理

    bzoj 500题纪念 总结一发题目吧,挑几道题整理一下,(方便拖板子) 1039:每条线段与前一条线段之间的长度的比例和夹角不会因平移.旋转.放缩而改变,所以将每条轨迹改为比例和夹角的序列,复制一份 ...

  6. 【sdoi2013】森林 BZOJ 3123

    Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数.第三行包含N个非负整数 ...

  7. 【清华集训】楼房重建 BZOJ 2957

    Description 小A的楼房外有一大片施工工地,工地上有N栋待建的楼房.每天,这片工地上的房子拆了又建.建了又拆.他经常无聊地看着窗外发呆,数自己能够看到多少栋房子. 为了简化问题,我们考虑这些 ...

  8. 【splay】文艺平衡树 BZOJ 3223

    Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3  ...

  9. bzoj 刷水

    bzoj 3856: Monster 虽然是sb题,,但是要注意h可能<=a,,,开始忘记判了WA得很开心. #include <iostream> #include <cst ...

随机推荐

  1. if else的执行流程

    int main(void) { int a, b; char op; float ans; scanf_s("%d%c%d",&a,&op,1,&b); ...

  2. c语言split的实现代码

    我们知道在其他语言中有split函数可以把一个字符串按你自己想要的分隔符分割成多个字符串并以列表的形式返回.但是对于c语言来说,是没有这样一个函数接口可以直接调用的.但是有时候在项目工作中,又会用到这 ...

  3. 使用Sqlserver事务发布实现数据同步(转)

    出处:http://www.cnblogs.com/daizhj/archive/2009/11/18/1605293.html 事务的功能在sqlserver中由来已久,因为最近在做一个数据同步方案 ...

  4. Mac10.9下的libtiff编译

    libtiff介绍 libtiff下载 libtiff编译 libtiff介绍? 参考:http://en.wikipedia.org/wiki/Tiff libtiff下载 直接到官网下载:http ...

  5. 【转】MOCK方法介绍

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://baidutech.blog.51cto.com/4114344/743740 1 ...

  6. 四则运算(Java) 陈志海 邓宇

    目录 Github项目地址 PSP表格 功能要求 题目 功能(已全部实现) 效能分析 设计实现过程 数值生成 算式生成 问题集生成 设计实现过程 代码说明 测试运行 代码覆盖率 项目小结 Github ...

  7. C#调用OCX控件的常用方法[转]

    小伙伴们在使用ICP提供的各种能力进行集成开发时常常会遇到一些技术上的困扰,例如ICP中很多接口是通过OCX控件的方式提供的,如何调用这些接口,就成了一个不大不小的问题,毕竟开发指南上可没这些内容啊~ ...

  8. ASP.NET MVC 开源建站系统 ZKEACMS 推荐,从此网站“拼”起来

    一个挺有意思的项目,跟拼图一样的创建网站,先来几张GIF感受一下: 官方地址:http://www.zkea.net/zkeacms 下载地址:https://github.com/SeriaWei/ ...

  9. 数组中 reduce累计运算

    let arr = [1,2,3,4]; let sum = (a, b) => a + b; arr.reduce(sum, 0); 最后输出10

  10. day02.1-字符串内置方法

    字符串——str的定义:test = "zizaijiapu" 特点:1. 字符串是可迭代对象: 2. 字符串中各元素是有序的: 3. 字符串一经创建,其内容值不可修改. 1. 查 ...