洛谷P3128 [USACO15DEC] Max Flow P && 树上差分

传送门:P3128 [USACO15DEC] Max Flow P

首先要学会差分qwq
然后要学会lca

题目意思:

给定一个节点数为 \(n\) 的树,有 \(m\) 次操作。
每次操作给你两个数 \(s\)\(t\),你需要在 \(s\)\(t\) 的路径所经过点的运输压力 \(+1\)
求最后运输压力最大的点的压力。

思路:

发现 \(s\)\(t\) 的路径为 \(s\to lca(s,t)\to t\)
那么我们可以建立一个差分数组 \(pres\)
每次操作在 \(s\to lca(s,t)\)\(t\to lca(s,t)\) 的路径经过的点上 +1,就是 \(pres_s+1\)\(pres_t+1\)\(pres_{lca(s,t)}-2\)

问题:

但是这样 lca(s,t) 相当于并没有 +1,为了解决这个问题,我们来看一张图:

现在所有的 \(pres\) 都是 \(0\)
此时我们想从 \(3\) 走到 \(1\)
很明显他们的 \(lca\)\(4\),按照上面的方法:我们能够得到:

这时开始遍历

void pressure(int now,int fa)
{
	for(int i=fir[now];i;i=ed[i].next)
	{
		if(ed[i].v!=fa)
		{
			pressure(ed[i].v,now);
			pres[now]+=pres[ed[i].v];
		}
	}
}

可以得到:
\(pres_1=1\)\(pres_5=1\)\(pres_3=1\)\(pres_4=0\)\(pres_2=0\)\(pres_7=0\)\(pres_6=0\)
观察到:pres_4 的值只会影响到他的父亲节点 6 的值,那么我们可以:
\(pres_4-1\)\(pres_6-1\)
这样就能得出正确答案了喵~

最终思路:

每次询问求 s 和 t 的 lca,\(pres_s+=1\)\(pres_t+=1\)\(pres_{lca(s,t)}-=1\)\(pres_{lca(s,t) 的 fa}-=1\)
最后遍历整棵树求最大值。

代码:

lca用的是倍增。

#include<bits/stdc++.h>

using namespace std;

const int maxn=50010;
const int maxm=100100;

int ans=-1;
int en;
int m,n; 
int fir[maxn];

struct edge{
	int v,next;
}ed[maxn*2];

void add_edge(int p1,int p2)
{
	en++;
	ed[en].v=p2;
	ed[en].next=fir[p1];
	fir[p1]=en;
}

int depth[maxn];
int f[maxn][25];

void dfs(int now,int fa)
{
	depth[now]=depth[fa]+1;
	f[now][0]=fa;
	for(int i=1;i<=20;i++)
	{
		f[now][i]=f[f[now][i-1]][i-1];
	}
	for(int i=fir[now];i;i=ed[i].next)
	{
		if(ed[i].v!=fa) dfs(ed[i].v,now);
	}
}

int get_lca(int a,int b)
{
	if(depth[a]<depth[b]) swap(a,b);//让 a 成为深度更大的点 
	for(int i=20;i>=0;i--)
	{
		if(depth[f[a][i]] >= depth[b]) 
			a=f[a][i];
	}
	if(a==b) return a;
	for(int i=20;i>=0;i--)
	{
		if(f[a][i]!=f[b][i])
			a=f[a][i],b=f[b][i];
	}
	return f[a][0];
}

int pres[maxn];

void pressure(int now,int fa)
{
	for(int i=fir[now];i;i=ed[i].next)
	{
		if(ed[i].v!=fa)
		{
			pressure(ed[i].v,now);
			pres[now]+=pres[ed[i].v];
		}
	}
	ans=max(ans,pres[now]);
}

int main()
{
	cin>>n>>m;
	for(int i=1;i<n;i++)
	{
		int p1,p2;
		cin>>p1>>p2;
		add_edge(p1,p2);
		add_edge(p2,p1);
	}
	dfs(1,0);
	for(int i=1;i<=m;i++)
	{
		int s,e;
		cin>>s>>e;
		int lca=get_lca(s,e);
		pres[s]++,pres[lca]--,pres[e]++,pres[f[lca][0]]--;
	//	cout<<lca<<endl;
	}
	pressure(1,0);cout<<ans<<endl;
	return 0;
}

完结撒花!!!

posted @ 2024-09-07 10:17  lazy_ZJY  阅读(4)  评论(0编辑  收藏  举报