USACO 2015 December Contest, Platinum

Problem 1. Max Flow

Farmer John has installed a new system of N−1 pipes to transport milk between the N stalls in his barn (2≤N≤50,000 ), conveniently numbered 1…N . Each pipe connects a pair of stalls, and all stalls are connected to each-other via paths of pipes.

FJ is pumping milk between K pairs of stalls (1≤K≤100,000 ). For the i th such pair, you are told two stalls si and ti , endpoints of a path along which milk is being pumped at a unit rate. FJ is concerned that some stalls might end up overwhelmed with all the milk being pumped through them, since a stall can serve as a waypoint along many of the K paths along which milk is being pumped. Please help him determine the maximum amount of milk being pumped through any stall. If milk is being pumped along a path from si to ti , then it counts as being pumped through the endpoint stalls si and ti , as well as through every stall along the path between them.

INPUT FORMAT (file maxflow.in):

The first line of the input contains N and K .

The next N−1 lines each contain two integers x and y (x≠y ) describing a pipe between stalls x and y .

The next K lines each contain two integers s and t describing the endpoint stalls of a path through which milk is being pumped.

OUTPUT FORMAT (file maxflow.out):

An integer specifying the maximum amount of milk pumped through any stall in the barn.

SAMPLE INPUT:

5 10
3 4
1 5
4 2
5 4
5 4
5 4
3 5
4 3
4 3
1 3
3 5
5 4
1 5
3 4

SAMPLE OUTPUT:

9

Problem credits: Brian Dean

译:

农夫约翰已经安装了N-1个管道系统给N(2≤N≤50,000)个摊位输送牛奶,方便编号为1... N。每个管道连接一对摊位,所有的摊位都通过管道路径连接起来。

FJ在K对点(1≤K≤100,000)之间抽取牛奶。对于第i个这样的对,你被告知两个点Si和Ti,表示抽取牛奶路径的两个端点,这一路径上都是同一个单位的费率。 FJ关注的是,一些点最终可能会被所有抽取的牛奶通过。请帮助他确定所有点可能通过的最多的牛奶量。如果牛奶正在沿着路径Si到Ti,则认为它将通过端点Si和Ti,以及通过沿它们之间的路径中的每个点。

INPUT FORMAT (file maxflow.in):

The first line of the input contains N and K.

第一行两个整数N和K

The next N−1 lines each contain two integers x and y (x≠y) describing a pipe between stalls x and y.

接下来N-1行,每行两个整数X和Y,描述被一个管子连接的两个点X和Y

The next K lines each contain two integers s and t describing the endpoint stalls of a path through which milk is being pumped.

接下来K行,每行两个整数 S和T,描述正在被抽取牛奶所在的两个端点

OUTPUT FORMAT (file maxflow.out):

An integer specifying the maximum amount of milk pumped through any stall in the barn.

输出一个整数,表示通过任意点所能抽取的最大牛奶数量。

树上查分

拿到这题第一反应显然是树剖。。但实际上有更加方便的做法,那就是树上差分。

首先我们联想一下对数列进行差分的做法。序列差分这个技巧一般适用于:执行若干次区间加减,到最后再统计每个点的权值。设T是A的差分序列,我们把将a~b这个区间中的每个点加上c的操作(A[i]+=c a<=i<=b)转变成对T的操作T[a]+=c,T[b+1]-=c,最后A[k]的值就是Sum{T[i]}(1<=i<=k)即T的一个前缀和。这个很容易能理解,随便在脑中yy一下或者画画图都能理解。

然后我们再来看下这道题。这道题与序列上有一定相似之处:执行若干次路径上的加减,最后统计每个点的权值。我们可以将在序列上进行差分的方法拓展到树上。对于s~t这个路径上每个点加上c的操作,我们可以对树A的“差分树”T进行操作:T[s]+=c,T[t]+=c,T[LCA(s,t)]-=c,T[Father[LCA(s,t)]]-=c。即给s这个点加上c,给t这个店加上c,给s和t的最近公共祖先和这个祖先的父亲减去c。最后每个点的权值就是这个点的子树权值之和。

这样做为什么是正确的呢?我们来yy一下一般情况:对于一棵树,从s走到t可以这么走:先从s走到LCA(s,t),再从t走到LCA(s,t)。为了更方便接下来的叙述,我们可以想象有两个人分别从s和t走到LCA(s,t)。然后,我们要将路径s~t上每个点加上c,因为我们最后统计的是每个点的子树权值之和,所以说白了就是这个标记要向它的父亲上传;所以当我们给s和t都加上c后,上传到LCA(s,t)的时候就变成了2c,显然在这里是要减去c的;而对于LCA(s,t)的父亲,由于LCA(s,t)的标记也要上传,所以在LCA(s,t)的父亲处再减去一个c。这段话比较长,但是只要深刻理解数列差分的技巧,理解树上差分也是很容易的。

最后说几个实现上的细节。

第一,对于LCA(s,t),如果它是根,那么就没有将它父亲减去c的操作了。

第二,最后子树统计的时候的方法比较多。可以用类似拓扑排序的思想,从最后一层结点“逐层上传”。也可以用树型dp。这个随个人喜好而定。

具体看代码~

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#define maxn 50010
#define maxk 100010
using namespace std;
int n,k,s,t,tot,lca,root=,ans=,f[maxn],deep[maxn],value[maxn],head[maxn],p[maxn][];
struct node{
int go,next;
}e[maxk];
inline int read(){
int x=,f=;char ch=getchar();
while (ch>'' || ch<''){if (ch=='-') f=-;ch=getchar();}
while (ch>='' && ch<=''){x=x*+ch-'';ch=getchar();}
return x*f;
}
inline void addedge(int &s,int &t){
e[++tot]=(node){t,head[s]};head[s]=tot;
e[++tot]=(node){s,head[t]};head[t]=tot;
}
void make_tree(int u,int fa){
int v;
for (int i=head[u];i;i=e[i].next){
v=e[i].go;
if (v!=fa){
deep[v]=deep[u]+;
f[v]=u;
make_tree(v,u);
}
}
}
void prepare(){
memset(p,-,sizeof(p));
for (int i=;i<=n;i++) p[i][]=f[i];
for(int j=;(<<j)<=n;j++)
for (int i=;i<=n;i++)
if (p[i][j-]!=-) p[i][j]=p[p[i][j-]][j-];
}
inline int LCA(int a,int b){
if (deep[a]<deep[b]) swap(a,b);
int t=trunc(log2(deep[a]));
for (int i=t;i>=;i--) if (deep[a]-(<<i)>=deep[b]) a=p[a][i];
if (a==b) return a;
for (int i=t;i>=;i--)
if (p[a][i]!=- && p[a][i]!=p[b][i]) a=p[a][i],b=p[b][i];
return p[a][];
}
int ask(int x){
for (int i=head[x];i;i=e[i].next){
if (f[x]!=e[i].go){
ask(e[i].go);
value[x]+=value[e[i].go];
}
}
ans=max(ans,value[x]);
}
int main(){
// freopen("maxflow.in","r",stdin);
// freopen("maxflow.out","w",stdout);
n=read();k=read();
for (int i=;i<n;i++){
s=read();t=read();
addedge(s,t);
}
deep[root]=;
make_tree(root,f[root]=);
prepare();
for (int i=;i<=k;i++){
s=read();t=read();
lca=LCA(s,t);
value[s]++;value[t]++;value[lca]--;value[f[lca]]--;
}
ask(root);
printf("%d\n",ans);
}

USACO December 铂金Maxflow的更多相关文章

  1. Usaco 2019 Jan Platinum

    Usaco 2019 Jan Platinum 要不是昨天老师给我们考了这套题,我都不知道usaco还有铂金这么一级. 插播一则新闻:杨神坚持认为铂金比黄金简单,原因竟是:铜 汞 银 铂 金(金属活动 ...

  2. USACO 2015 December Contest, Gold Problem 2. Fruit Feast

    Problem 2. Fruit Feast 很简单的智商题(因为碰巧脑出来了所以简单一,一 原题: Bessie has broken into Farmer John's house again! ...

  3. USACO 2015 December Contest, Platinum Problem Max Flow【树链剖分】

    题意比较难理解,就是给你n个点的树,然后给你m个修改操作,每一次修改包括一个点对(x, y),意味着将x到y所有的点权值加一,最后问你整个树上的点权最大是多少. 比较裸的树链剖分了,感谢Haild的讲 ...

  4. USACO 2019 December Contest 随记

    Forewords 今年 USACO 的比赛变化挺大的,有部分分了,而且不再是固定十个点了(部分分只说这几个点满足这几个性质,以为十个点的我还高兴了一会,一提交,...),除此之外居然赛后还排名了.这 ...

  5. [USACO 2018 December Contest]作业总结

    t1 Convention 题目大意 每一头牛都有一个来的时间,一共有\(n\)辆车,求出等待时间最长的那头牛等待的最小时间. 解法 第一眼看到这道题还以为是\(2018noip\)普及组的t3魔鬼题 ...

  6. USACO 2012 December ZQUOJ 24122 Scrambled Letters(二分)

    题意:有一个字典序名单,现在把这些名单的顺序和名字的字符顺序扰乱了,要输出原先的名字在原来的名单中的最低和最高位置. 分析:先将所有的名字串按字典序从小到大和从大到小分别排序smin[]和smax[] ...

  7. USACO 2012 December ZQUOJ 24128 Wifi Setup(动态dp)

    题意:给出在同一条直线上的n个点和两个数A,B,现在要在这条直线上放置若干个信号塔,每个信号塔有一个r值,假设它的位置是x,则它能覆盖的范围是x-r~x+r,放置一个信号塔的花费是A+B*r,问要覆盖 ...

  8. USACO 铂金 T1

    题意 给出一个数轴,每次可以选择停下并得到当前点的收益,或者继续随机向左右游走,走到边界游戏结束收益为0. 求从每个点出发的最大期望收益.(n<=1e5) 有一个显然的dp方程 这个方程是带环的 ...

  9. [Poj3261] [Bzoj1717] [后缀数组论文例题,USACO 2006 December Gold] Milk Patterns [后缀数组可重叠的k次最长重复子串]

    和上一题(POJ1743,上一篇博客)相似,只是二分的判断条件是:是否存在一段后缀的个数不小于k #include <iostream> #include <algorithm> ...

随机推荐

  1. 从hash算法到java hashcode()

    转载 https://blog.csdn.net/Walk_er/article/details/74976146 hash算法是一个摘要算法(yy:描述性算法:可以给一个物体确切的描述,但是不能通过 ...

  2. WordCount改进 小组项目

    GitHub地址:https://github.com/DM-Star/WordCount-opt 作业需求:http://www.cnblogs.com/ningjing-zhiyuan/p/865 ...

  3. 爬虫之mongodb数据库

    一 mongodb的介绍 1.易用性:mongodb是一款强大.灵活并且易扩展的数据库.他面向于文档的数据库,而不是关系性数据库.不采用关系型主要是为了获得更好的扩展性.还有一个好处就是面向文档的数据 ...

  4. GDBT

    理论知识: 第四范式自主研发算法GBDT(Gradient Boosting Decision Tree) GBDT是一种基分类器为决策树的集成学习方法.决策树是一种常见的机器学习算法,GBDT中使用 ...

  5. 2018.11.04 洛谷P1081 开车旅行(倍增)

    传送门 思路简单码量超凡? 感觉看完题大家应该都知道是倍增sbsbsb题了吧. 首先预处理出从每个点出发如果是AAA走到哪个点,如果是BBB走到哪个点. 然后利用刚刚预处理出的信息再预处理从每个点出发 ...

  6. Java基础语法学习知识

    基础概念 标识符1.由字母,数字,下划线,美元符组成2.首字母不能是数字3.不能是关键字和保留字4.能反映其作用 关键字1.有特定含义2.用于特定地方3.用来命名标识符 常量1.程序执行时值不变的量2 ...

  7. Educational Codeforces Round 61 F 思维 + 区间dp

    https://codeforces.com/contest/1132/problem/F 思维 + 区间dp 题意 给一个长度为n的字符串(<=500),每次选择消去字符,连续相同的字符可以同 ...

  8. Educational Codeforces Round 51 F. The Shortest Statement(lca+最短路)

    https://codeforces.com/contest/1051/problem/F 题意 给一个带权联通无向图,n个点,m条边,q个询问,询问两点之间的最短路 其中 m-n<=20,1& ...

  9. DevExpress 只允许修改指定列

    gridView1.OptionsBehavior.Editable = true; gridView1.OptionsBehavior.ReadOnly = false; foreach (Grid ...

  10. TCP/IP协议(3):数据链路层

    OSI数据链路层上的协议有Ethernet/IEEE802.3/IEEE802.4/IEEE802.5. ARP.RARP等. 1.Ethernet(以太网) 链路层支持很多协议,比如Ethernet ...