其他分享
首页 > 其他分享> > Maxflow

Maxflow

作者:互联网

题目背景
给你一棵大小为 \(n\) 的树,每个节点上都有一个点权,初值为 0。

一共有 \(m\) 次操作,每次操作给定一个点对 $(s_i,t_i)#,表示对 \(s_i−>t_i\) 这条路径上的每个节点点权+1。

所有操作结束后,询问所有点的最大点权。

输入格式
第一行包括两个正整数 \(n,m\)。

此后 \(n−1\) 行,每行两个正整数,描述着这颗树上的 \(n−1\) 条边。

再此后的 \(m\) 行,每行两个正整数 \(s_i,t_i\),描述一个操作的给定点对。

输出格式
输出一行一个正整数,表示操作后所有点的最大点权。

样例
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

output

9

数据范围
时间限制: 1s
空间限制: 256MB
对于 100% 的数据, \(n,m≤100,000\)。

数据富含梯度,可以各种尝试。

树上差分的模板。

首先既然是差分,那么就以子树和为这个点的权值。首先两个点都增加1,到他们的LCA时差分值减1,LCA的父亲差分值也要减1.

用倍增\(O(nlogn)\),用Tarjan \(O(n)\)

#include<cstdio>
#include<iostream>
using namespace std;
const int N=1e5+5;
int n,m,lg[N],dep[N],fa[N][30],hd[N],c[N],s,t,ans,k;
struct edge{
	int v,nxt;
}e[N<<1];
void add_edge(int z,int x,int y)
{
	e[z]=(edge){y,hd[x]};
	hd[x]=z;
}
void dfs(int x,int y)
{
	fa[x][0]=y,dep[x]=dep[y]+1;
	for(int i=1;i<=lg[dep[x]];i++)
		fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int i=hd[x];i;i=e[i].nxt)
		if(e[i].v!=y)
			dfs(e[i].v,x);
}
int lca(int x,int y)
{
	while(dep[x]>dep[y])
		x=fa[x][lg[dep[x]-dep[y]]];
	while(dep[x]<dep[y])
		y=fa[y][lg[dep[y]-dep[x]]];
	if(x==y)
		return x;
	for(int i=lg[dep[x]];i>=0;i--)
		if(fa[x][i]!=fa[y][i])
			x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
int sou(int x)
{
	int s=0;
	for(int i=hd[x];i;i=e[i].nxt)
		if(e[i].v!=fa[x][0])
			s+=sou(e[i].v);
	s+=c[x];
	ans=max(ans,s);
	return s;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		scanf("%d%d",&s,&t);
		add_edge(i<<1,s,t);
		add_edge(i<<1|1,t,s);
	}
	for(int i=2;i<=n;i++)
		lg[i]=lg[i>>1]+1;
	dfs(1,0);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&s,&t),k=lca(s,t);
		c[s]++,c[t]++,c[k]--,c[fa[k][0]]--;
	}
	sou(1);
	printf("%d",ans);
	return 0;
}

标签:正整数,fa,int,点权,dep,ans,Maxflow
来源: https://www.cnblogs.com/mekoszc/p/16209358.html