洛谷P3128 [USACO15DEC]Max Flow P/树上差分模板
原题链接
题意:
给定一棵n个点的树,n-1条无向边,有k次询问,每次给两个点x、y,将这两个点的最短路径经过的每个点+1(包括x,y),求经过次数最多的那个点经过了多少次。
数据范围:
\(2≤n≤50,000\)
\(1≤k≤100,000\)
思路:
一看这数据就不能用暴力了,肯定得用差分。
很明显这就是点的差分模板题啊!
把x,y两个点前缀和数组+1,把\(LCA(x,y)\)以及\(LCA(x,y)\)的父亲节点-1,
好了,这就结束了。
code:
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <queue>
using namespace std;
const int N=100005;
const int M=25;
int cnt,head[N],fa[N][M],total[N],n,m,dep[N],b[N];
struct node{
int u,v,w,next;
}ed[N];
void add_edge(int u,int v)
{
cnt++;
ed[cnt].u=u;
ed[cnt].v=v;
ed[cnt].next=head[u];
head[u]=cnt;
}
void dfs(int xx)//本次DFS是求出倍增数组dou[][]
{
for(int i=1;i<=20;i++)
{
fa[xx][i]=fa[fa[xx][i-1]][i-1];
}
for(int i=head[xx];i;i=ed[i].next)
{
int temp=ed[i].v;
if(!b[temp])
{
b[temp]=1;
dep[temp]=dep[xx]+1;
dou[temp][0]=xx;
dfs(temp);
}
}
}
int LCA(int x,int y)
{
if(dep[x]<dep[y])
{
swap(x,y);
}
int temp=dep[x]-dep[y];
for(int i=20;i>=0;i--)
{
if((1<<i)&temp)
{
x=fa[x][i];
}
}
if(x==y)
return x;
for(int i=20;i>=0;i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
void dfs2(int xx)//本次DFS求出前缀和数组
{
for(int i=head[xx];i;i=ed[i].next)
{
int temp=ed[i].v;
if(!b[temp])
{
b[temp]=1;
dfs2(temp);
total[xx]+=total[temp];
}
}
}
int main()
{
cin>>n>>m;
for(int i=1;i<n;i++)
{
int x,y;
cin>>x>>y;
add_edge(x,y);
add_edge(y,x);
}
b[1]=1;
dep[1]=1;
dfs(1);
memset(b,0,sizeof b);
while(m--)
{
int xx,yy;
cin>>xx>>yy;
int lca=LCA(xx,yy);
total[xx]++;
total[yy]++;
total[lca]--;
total[fa[lca][0]]--;
}
b[1]=1;
dfs2(1);
int maxn=0;
for(int i=1;i<=n;i++)
{
maxn=max(maxn,total[i]);
}
cout<<maxn;
return 0;
}