USACO December 铂金Maxflow

 

USACO 2015 December Contest, Platinum

 

Problem 1. Max Flow 

Farmer John has installed a new system of N1 pipes to transport milk between the N stalls in his barn (2N50,000 ), conveniently numbered 1N . 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 (1K100,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 N1 lines each contain two integers x and y (xy ) 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个管道系统给N2N50,000)个摊位输送牛奶,方便编号为1... N。每个管道连接一对摊位,所有的摊位都通过管道路径连接起来。

 

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

 

INPUT FORMAT (file maxflow.in):

 

The first line of the input contains N and K.

 

第一行两个整数NK

 

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

 

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

 

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行,每行两个整数 ST,描述正在被抽取牛奶所在的两个端点

 

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=1,ans=0,f[maxn],deep[maxn],value[maxn],head[maxn],p[maxn][20];
struct node{
    int go,next;
}e[maxk];
inline int read(){
    int x=0,f=1;char ch=getchar();
    while (ch>'9' || ch<'0'){if (ch=='-') f=-1;ch=getchar();}
    while (ch>='0' && ch<='9'){x=x*10+ch-'0';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]+1;
            f[v]=u;
            make_tree(v,u);
        }
    }
}
void prepare(){
    memset(p,-1,sizeof(p));
    for (int i=1;i<=n;i++) p[i][0]=f[i];
    for(int j=1;(1<<j)<=n;j++)
        for (int i=1;i<=n;i++)
            if (p[i][j-1]!=-1) p[i][j]=p[p[i][j-1]][j-1];
}
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>=0;i--) if (deep[a]-(1<<i)>=deep[b]) a=p[a][i];
    if (a==b) return a;
    for (int i=t;i>=0;i--)
        if (p[a][i]!=-1 && p[a][i]!=p[b][i]) a=p[a][i],b=p[b][i];
    return p[a][0];
}
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=1;i<n;i++){
        s=read();t=read();
        addedge(s,t);
    }
    deep[root]=1;
    make_tree(root,f[root]=0);
    prepare();
    for (int i=1;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);
}
View Code

 

转载于:https://www.cnblogs.com/fqqq/p/5149246.html

### 回答1: USACO 2021年12月是美国计算机奥林匹克竞赛的一次比赛,是为了选拔美国高中生中最优秀的计算机科学家而举办的。比赛包括四个不同难度级别的编程题目,参赛者需要在规定时间内完成这些题目。这次比赛的题目难度较高,需要参赛者具备较强的编程能力和算法思维能力。 ### 回答2: usaco是一个很受欢迎的美国高中生和大学生参加的计算机竞赛,每年会有四场不同的赛事,分为铜组、银组、金组和白银组等4个不同级别。2021年12月的usaco比赛题目难度中等,共4道算法题,主要涉及搜索算法、贪心算法、动态规划和图论算法等方面内容。 题目一是“Convenience Store”,给定一个城市地图,其中包含n个建筑,每个建筑位置有xy坐标,建筑之间可能有道路连通,每个建筑中包含一个便利店和售货员,售货员需要把货物直接送到顾客的门口并统计物资,问售货员需要访问哪些建筑才能完成任务。 题目二是“Longest Path Game”,给定一个有向无环图和起点和终点,每次可以走向图中指向该点的其他点,每走一步需要支付一定的代价,问从起点到终点最少需要支付多少代价并给出最少花费路径。 题目三是“Escape”,给定一个大小为n*m的迷宫,其中包含空地和只能通过特殊方式通过的障碍物,新增一个道具可以消除障碍物,在指定时间内到达终点即可获胜,问是否存在可行解。 题目四是“New Year Travel”,给定一个n个城市构成的圆环和m条单向道路,初次n个城市顺时针排列,经过m次之后重排该圆环,问是否存在一条路径可以在经过圆环的最小路程的前提下遍历所有的城市。 ### 回答3: USACO 2021 12月是一次由美国计算机科学奥林匹克联赛(USACO)组织的编程竞赛。USACO是美国高中生最具影响力的计算机竞赛之一,每年分为四个季度,包含铜组、银组、金组和白金组,涵盖了算法设计、数据结构、图论、搜索、动态规划、计算几何、图像处理等多个领域和真实场景。 本场比赛共有铜组、银组和金组三个组别,其中铜组和银组为在线比赛,金组为24小时比赛。比赛难度较高且时间较紧,需要选手在有限时间内完成一系列复杂的程序设计题目。在比赛期间,选手需要具备良好的分析问题、设计算法和编写程序的能力,同时还需要有过硬的数学基础、英语阅读理解能力和编程实践经验。 对于铜组选手来说,需要能够熟练使用基本算法和数据结构来解决题目,如模拟、暴力搜索、递推等;对于银组选手,则需要有更深入的算法思考和程序实现能力,如分治、贪心、二分、动态规划等;而针对金组选手,需要更高的算法挑战和程序优化能力,如图论、网络流、计算几何等。 此次USACO 2021 12月比赛题目难度较大,需要选手们具备扎实的算法基础和良好的程序设计习惯。要想在比赛中取得好成绩,需要选手们克服紧张心理,在比赛前加强对算法知识和代码实践的学习,时刻保持冷静,清晰思路,在有限时间内充分展现自己的编程才能和思维能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值