洛谷P3128 [USACO15DEC]最大流Max Flow_树链剖分

题目描述

Farmer John has installed a new system of  N-1 N1 pipes to transport milk between the  N N stalls in his barn ( 2 \leq N \leq 50,000 2N50,000), conveniently numbered  1 \ldots N 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 K pairs of stalls ( 1 \leq K \leq 100,000 1K100,000). For the  i ith such pair, you are told two stalls  s_i si and  t_i 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 Kpaths 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  s_i si to  t_i ti, then it counts as being pumped through the endpoint stalls  s_i si and

t_i ti, as well as through every stall along the path between them.

FJ给他的牛棚的N(2≤N≤50,000)个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。

FJ有K(1≤K≤100,000)条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。

输入输出格式

输入格式:

The first line of the input contains  N N and  K K.

The next  N-1 N1 lines each contain two integers  x x and  y y ( x \ne y xy) describing a pipe

between stalls  x x and  y y.

The next  K K lines each contain two integers  s s and  t t describing the endpoint

stalls of a path through which milk is being pumped.

输出格式:

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

barn.

输入输出样例

输入样例#1: 
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
输出样例#1: 
9

这题显然是个 树上差分+LCA ,我以前也写过一篇博客将这种方法怎么敲。

最近学了树剖,天天 剖来剖去 ,脑子都剖坏了,看到了这题,突发奇想,用了 树剖,还 AC 了。。。

附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#define LSON rt<<1
#define RSON rt<<1|1
#define DATA(x) b[x].data
#define SIGN(x) b[x].c
#define LSIDE(x) b[x].l
#define RSIDE(x) b[x].r
#define WIDTH(x) (RSIDE(x)-LSIDE(x)+1)
#define MAXN 50010
using namespace std;
int n,m,c=1,d=1;
int head[MAXN],deep[MAXN],size[MAXN],son[MAXN],top[MAXN],fa[MAXN],id[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;
}
inline int max(const int a,const int b){if(a>b)return a;return b;}
void pushup(int rt){
	DATA(rt)=max(DATA(LSON),DATA(RSON));
}
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);
}
void add(int u,int v){
	a[c].to=v;
	a[c].next=head[u];
	head[u]=c++;
	a[c].to=u;
	a[c].next=head[v];
	head[v]=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[will]>size[son[rt]])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!=son[rt]&&will!=fa[rt])
		dfs2(will,will);
	}
}
void work1(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[y],id[x],1,1);
	return;
}
void work(){
	int x,y;
	while(m--){
		x=read();y=read();
		work1(x,y);
	}
	printf("%d\n",DATA(1));
}
void init(){
	int u,v;
	n=read();m=read();
	for(int i=1;i<n;i++){
		u=read();v=read();
		add(u,v);
	}
	deep[1]=1;
	dfs1(1);
	dfs2(1,1);
	buildtree(1,n,1);
}
int main(){
	init();
	work();
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值