题目
题目
题目大意:
FJ给他的牛棚的N(2≤N≤50,000)个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。
FJ有K(1≤K≤100,000)条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。
题解
此题不需要在线修改,所以不需要树剖(我也不会树剖),直接用树上差分即可。
开一个差分数组a,比如在点u和v之间施加压力那么就执行
int t=lca(u,v);
a[u]++;
a[v]++;
a[t]--;
a[f[t][0]]--; //f[t][0]意为t的父节点
最后输出之前,执行一次树上dfs,把差分数组求个前缀和,统计下最大值就行了。
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
const int N=1E6;
int a[N],maxn;
int head[N],nxt[N],to[N],cnt;
int n,m,s,d[N],dep;
int f[N][21];
bool v[N];
queue<int> q;
void add(int x,int y) { //还是使用链式前向星
to[++cnt]=y;
nxt[cnt]=head[x];
head[x]=cnt;
}
int lca(int x,int y) {
if(d[x]>d[y]) swap(x,y);
for(int i=dep;i>=0;i--)
if(d[f[y][i]]>=d[x]) y=f[y][i];
if(x==y) return x;
for(int i=dep;i>=0;i--)
if(f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
void bfs() {
q.push(s);
d[s]=1;
while(!q.empty()) {
int t=q.front();
q.pop();
for(int i=head[t];i;i=nxt[i]) {
int y=to[i];
if(d[y]) continue;
d[y]=d[t]+1;
f[y][0]=t;
for(int j=1;j<=dep;j++)
f[y][j]=f[f[y][j-1]][j-1];
q.push(y);
}
}
}
void dfs(int x) {
v[x]=true;
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(v[y])
continue;
dfs(y);
a[x]+=a[y];
}
maxn=max(maxn,a[x]);
}
int main() {
scanf("%d%d",&n,&m);
s=1; //根结点随便取
dep=log2(n)+1;
for(int i=1;i<=n-1;i++) {
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
bfs();
while(m--) {
int x,y;
scanf("%d%d",&x,&y);
int t=lca(x,y); //萌新,不会lca的离线tarjan算法
a[t]--;
a[f[t][0]]--;
a[x]++;
a[y]++;
}
dfs(s);
printf("%d",maxn);
return 0;
}
易错点
最后,记录一下我之前错误的原因。
是把
void dfs(int x) {
v[x]=true;
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(v[y])
continue;
dfs(y);
a[x]+=a[y];
}
maxn=max(maxn,a[x]);
}
写成了
void dfs(int x) {
for(int i=head[x];i;i=nxt[i]) {
int y=to[i];
if(v[y])
continue;
v[y]=true; //这儿不同哦
dfs(y);
a[x]+=a[y];
}
maxn=max(maxn,a[x]);
}
这样子的话根结点可能会统计两遍,那么最后的最大值也就不同了。