BZOJ4390: [Usaco2015 dec]Max Flow

Description

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 KK pairs of stalls (1≤K≤100,000). For the iith such pair, you are told two stalls sisi and titi, 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 KK 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 sisi to titi, then it counts as being pumped through the endpoint stalls sisi and titi, as well as through every stall along the path between them.

给定一棵有N个点的树,所有节点的权值都为0。

有K次操作,每次指定两个点s,t,将s到t路径上所有点的权值都加一。

请输出K次操作完毕后权值最大的那个点的权值。

Input

The first line of the input contains NN and KK.

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

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

Output

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
题解Here!
解法一:
首先想到的就是 树链剖分/LCT。。。
附代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 50010
using namespace std;
int n,m,c=1,d=1;
int head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],id[MAXN],top[MAXN];
struct node1{
int next,to;
}a[MAXN<<1];
struct node2{
int data,c,l,r;
}b[MAXN<<2];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
namespace ST{
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) a[x].data
#define SIGN(x) a[x].c
#define LSIDE(x) a[x].l
#define RSIDE(x) a[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
struct Segment{
int data,c,l,r;
}a[MAXN<<2];
inline void pushup(int rt){
DATA(rt)=max(DATA(LSON),DATA(RSON));
}
inline void pushdown(int rt){
if(!SIGN(rt)||LSIDE(rt)==RSIDE(rt))return;
SIGN(LSON)+=SIGN(rt);DATA(LSON)+=SIGN(rt);
SIGN(RSON)+=SIGN(rt);DATA(RSON)+=SIGN(rt);
SIGN(rt)=0;
}
void buildtree(int l,int r,int rt){
int mid;
LSIDE(rt)=l;
RSIDE(rt)=r;
if(l==r){
DATA(rt)=0;
return;
}
mid=l+r>>1;
buildtree(l,mid,LSON);
buildtree(mid+1,r,RSON);
pushup(rt);
}
void update(int l,int r,int c,int rt){
int mid;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r){
SIGN(rt)+=c;DATA(rt)+=c;
return;
}
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)update(l,r,c,LSON);
if(mid<r)update(l,r,c,RSON);
pushup(rt);
}
int query(int l,int r,int rt){
int mid,ans=0;
if(l<=LSIDE(rt)&&RSIDE(rt)<=r)return DATA(rt);
pushdown(rt);
mid=LSIDE(rt)+RSIDE(rt)>>1;
if(l<=mid)ans=max(ans,query(l,r,LSON));
if(mid<r)ans=max(ans,query(l,r,RSON));
return ans;
}
void work_add(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
update(id[top[x]],id[x],1,1);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
update(id[x],id[y],1,1);
return;
}
}
inline void add(int x,int y){
a[c].to=y;a[c].next=head[x];head[x]=c++;
a[c].to=x;a[c].next=head[y];head[y]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
id[rt]=d++;top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])
dfs2(will,will);
}
}
void work(){
int x,y;
while(m--){
x=read();y=read();
ST::work_add(x,y);
}
printf("%d\n",ST::query(1,n,1));
}
void init(){
int x,y;
n=read();m=read();
for(int i=1;i<n;i++){
x=read();y=read();
add(x,y);
}
deep[1]=1;
dfs1(1);
dfs2(1,1);
ST::buildtree(1,n,1);
}
int main(){
init();
work();
return 0;
}

总耗时3244ms。

解法二:

这题可以不用在线做,那么我们就有一个很NOIP的算法——树上差分

若操作的节点是u,v,那么只要在差分数组num[]中这样:

int lca=LCA(u,v);
num[u]++;num[v]++;
num[lca]--;num[fa[lca]]--;

最后再用一个dfs求出和:

void get_sum(int rt){
sum[rt]=num[rt];
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will==fa[rt])continue;
get_sum(will);
sum[rt]+=sum[will];
}
ans=max(ans,sum[rt]);
}

这样,sum[]数组中就是权值了。

那个LCA我不管你怎么求,反正什么倍增啊,树剖啊什么乱七八糟的玩意搞出来就行了。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define MAXN 50010
using namespace std;
int n,m,c=1,ans=0;
int num[MAXN],sum[MAXN],head[MAXN],deep[MAXN],son[MAXN],size[MAXN],fa[MAXN],top[MAXN];
struct node{
int next,to;
}a[MAXN<<1];
inline int read(){
int date=0,w=1;char c=0;
while(c<'0'||c>'9'){if(c=='-')w=-1;c=getchar();}
while(c>='0'&&c<='9'){date=date*10+c-'0';c=getchar();}
return date*w;
}
inline void add(int x,int y){
a[c].to=y;a[c].next=head[x];head[x]=c++;
a[c].to=x;a[c].next=head[y];head[y]=c++;
}
void dfs1(int rt){
son[rt]=0;size[rt]=1;
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(!deep[will]){
deep[will]=deep[rt]+1;
fa[will]=rt;
dfs1(will);
size[rt]+=size[will];
if(size[son[rt]]<size[will])son[rt]=will;
}
}
}
void dfs2(int rt,int f){
top[rt]=f;
if(son[rt])dfs2(son[rt],f);
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will!=fa[rt]&&will!=son[rt])
dfs2(will,will);
}
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])swap(x,y);
x=fa[top[x]];
}
if(deep[x]>deep[y])swap(x,y);
return x;
}
void get_sum(int rt){
sum[rt]=num[rt];
for(int i=head[rt];i;i=a[i].next){
int will=a[i].to;
if(will==fa[rt])continue;
get_sum(will);
sum[rt]+=sum[will];
}
ans=max(ans,sum[rt]);
}
void work(){
int x,y;
while(m--){
x=read();y=read();
int lca=LCA(x,y);
num[x]++;num[y]++;num[lca]--;num[fa[lca]]--;
}
get_sum(1);
printf("%d\n",ans);
}
void init(){
int x,y;
n=read();m=read();
for(int i=1;i<n;i++){
x=read();y=read();
add(x,y);
}
deep[1]=1;
dfs1(1);
dfs2(1,1);
}
int main(){
init();
work();
return 0;
}

总耗时:780ms

由此,我们可以看到,树上差分的速度几乎是树剖的4倍!

在NOIP这种严重卡常的比赛中,不到万不得已,不要用两个log的算法。。。

BZOJ4390: [Usaco2015 dec]Max Flow的更多相关文章

  1. bzoj4390: [Usaco2015 dec]Max Flow(LCA+树上差分)

    题目大意:给出一棵树,n(n<=5w)个节点,k(k<=10w)次修改,每次给定s和t,把s到t的路径上的点权+1,问k次操作后最大点权. 对于每次修改,给s和t的点权+1,给lca(s, ...

  2. BZOJ 4390: [Usaco2015 dec]Max Flow

    4390: [Usaco2015 dec]Max Flow Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 177  Solved: 113[Submi ...

  3. [Usaco2015 dec]Max Flow 树上差分

    [Usaco2015 dec]Max Flow Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 353  Solved: 236[Submit][Sta ...

  4. 【bzoj4390】[Usaco2015 dec]Max Flow LCA

    题目描述 Farmer John has installed a new system of N−1 pipes to transport milk between the N stalls in h ...

  5. [Usaco2015 dec]Max Flow

    Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 204  Solved: 129[Submit][Status][Discuss] Descriptio ...

  6. 【BZOJ4391】[Usaco2015 dec]High Card Low Card(贪心)

    [BZOJ4391][Usaco2015 dec]High Card Low Card(贪心) 题面 BZOJ 题解 预处理前缀后缀的结果,中间找个地方合并就好了. #include<iostr ...

  7. bzoj4393: [Usaco2015 Dec]Fruit Feast

    题意: T,A,B.T是上限.A和B可以随意吃但是不能超过T.有一次将吃的东西/2的机会.然后可以继续吃,不能超过T.问最多可以吃多少. =>我们先处理不能/2可以吃到哪些.然后弄个双指针扫一扫 ...

  8. USACO Max Flow

    洛谷 P3128 [USACO15DEC]最大流Max Flow 洛谷传送门 JDOJ 3027: USACO 2015 Dec Platinum 1.Max Flow JDOJ传送门 Descrip ...

  9. 洛谷P3128 [USACO15DEC]最大流Max Flow [树链剖分]

    题目描述 Farmer John has installed a new system of  pipes to transport milk between the  stalls in his b ...

随机推荐

  1. Codeforces Round #324 (Div. 2) Dima and Lisa 哥德巴赫猜想

    原题链接:http://codeforces.com/contest/584/problem/D 题意: 给你一个奇数,让你寻找三个以内素数,使得和为这个奇数. 题解: 这题嘛...瞎比搞搞就好,首先 ...

  2. 你知道如何在springboot中使用redis吗

    特别说明:本文针对的是新版 spring boot 2.1.3,其 spring data 依赖为 spring-boot-starter-data-redis,且其默认连接池为 lettuce ​  ...

  3. 【转】java:多网卡环境下获取MAC地址

    http://blog.csdn.net/10km/article/details/78569962 JDK6以后 java.net.NetworkInterface提供了完整的方法用于获取网络设备信 ...

  4. 聊聊、Zookeeper 数据结构和操作命令

    Zookeeper 的视图结构跟标准的 Unix 文件系统很像,都有一个根节点 / .在根节点下面就是一个个的子节点,我们称为 ZNode.ZNode 是 Zookeeper 中最小数据单位,在 ZN ...

  5. 聊聊、Zookeeper Windows启动

    Apache ZooKeeper is an effort to develop and maintain an open-source server which enables highly rel ...

  6. Blocks的申明调用与Queue当做锁的用法

    Blocks的申明与调用 话说Blocks在方法内使用还是挺方便的,之前都是把相同的代码封装成外部函数,然后在一个方法里需要的时候调用,这样挺麻烦的.使用Blocks之后,我们可以把相同代码在这个方法 ...

  7. Retrofit 使用flatmap操作符时处理错误、异常

    在实际项目(Retrofit+RxJava框架)中,有时需要先登录,获取token后再去获取用户信息,此时我们使用flatmap操作符比较好. 在RESTResult对象里,包括请求返回的状态:失败还 ...

  8. Oracle 11gR2 RAC 单网卡 转 双网卡绑定 配置步骤

    之前写过一篇双网卡绑定的文章,如下: Oracle RAC 与 网卡绑定 http://blog.csdn.net/tianlesoftware/article/details/6189639 Ora ...

  9. js 淘宝评分

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  10. ionic 调试 "死亡白屏"

    死亡白屏(White Screen of Death) 我想“死亡白屏”应该是不需要解释的,开发过ionic app的童鞋应该都有遇到过,这里解释以防读者没有听说过:“可能在浏览器中调试时一切正常,当 ...