P3128 [USACO15DEC]最大流Max Flow

P3128 [USACO15DEC]最大流Max Flow

对,这是一道最大流的题目qwq

树上跑最大流,没错

也就是跑最小割

你看名字里都有最大流,为什么不能跑最大流qwq..............................
编不下去了

跑树上差分。

就像数组上可以进行差分一样,树上也可以进行差分。适用于树上两点之间的路径操作,和极少数的查询

适用于维护路径长可以进行结合律的操作

比如说我们要在树上进行两点之间的路径上的节点值加一个数,最后输出所有节点值之和。

我们可以进行树链剖分,可是使用树链剖分有些大材小用了,而且常数巨大

我们就可以使用差分

比如说这么一棵树

我们要使得8到11的路径上的点加3

我们就可以设一个数组,\(t[i]\)表示这棵树的差分数组,\(st[i][j]\)表示树上的倍增数组

然后我们令\(t[8]+=3,t[11]+=3,t[lca_{(8,11)}]-=3,t[st[lca_{(8,11)}][0]]-=3\)

然后我们将差分数组使用以下程序进行整理整理,然后进行查询。


void DFS(int now,int fa)
{
	int pas=0;
	for(int i=head[now];i;i=line[i].nxt)
		if(line[i].p!=fa)
		{
			DFS(line[i].p,now);
			t[now]+=t[line[i].p];
		}
}

将所有点上的值递归加起来,就成了下图的情况。成功实现了O(1)修改,O(N)查询


而对于维护边权呢?我们可以将边权下放至所连点中深度最深的点上去

然后将差分时的\(t[st[lca_{(a,b)}][0]]-=add,t[lca_{(a,b)}]-=add\)变为\(t[lca_{(a,b)}]-add*2\)就可以了,树链剖分也可以将边权下放至点

此题\(code\)

#include<cstdio>
#include<algorithm>
#include<iostream>
using std::swap;
using std::max;
const int maxn=50100;
struct node
{
	int p;
	int nxt;
};
node line[maxn<<1];
int head[maxn],tail;
void add(int a,int b)
{
	line[++tail].p=b;
	line[tail].nxt=head[a];
	head[a]=tail;
}
int st[maxn][20];
int log[maxn];
int dep[maxn];
int ans,t[maxn];
void dfs(int now,int fa)
{
	st[now][0]=fa;
	dep[now]=dep[fa]+1;
	for(int i=1;i<=log[dep[now]];i++)
		st[now][i]=st[st[now][i-1]][i-1];
	for(int i=head[now];i;i=line[i].nxt)
		if(line[i].p!=fa)
			dfs(line[i].p,now);
}
int lca(int a,int b)
{
	if(dep[a]<dep[b])	swap(a,b);
	for(int i=log[dep[a]];i>=0;i--)
		if(dep[st[a][i]]>=dep[b])
			a=st[a][i];
	if(a==b)	return a;
	for(int i=log[dep[a]];i>=0;i--)
		if(st[a][i]!=st[b][i])
			a=st[a][i],b=st[b][i];
	return st[a][0];
}
void DFS(int now,int fa)
{
	int pas=0;
	for(int i=head[now];i;i=line[i].nxt)
		if(line[i].p!=fa)
		{
			DFS(line[i].p,now);
			t[now]+=t[line[i].p];
		}
	ans=max(ans,t[now]);
}
int main()
{
	int n,k;
	scanf("%d%d",&n,&k);
	for(int i=2;i<=n;i++)	log[i]=log[i>>1]+1;
	int a,b;
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&a,&b);
		add(a,b);add(b,a);
	}
	dfs(1,0);
	for(int i=1;i<=k;i++)
	{
		scanf("%d%d",&a,&b);
		t[a]++;t[b]++;
		int LCA=lca(a,b);
		t[LCA]--;	
		t[st[LCA][0]]--;
	}
	DFS(1,0);
	printf("%d",ans);
}
posted @ 2018-08-01 18:33  Lance1ot  阅读(286)  评论(0编辑  收藏  举报