【题目描述】
FJ给他的牛棚的N(2≤N≤50,000)个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。
FJ有K(1≤K≤100,000)条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。
【样例输入】
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
【样例输出】
9
【题意分析】
给你一棵树,每次操作就是把树上一点到一点的路径都加上一
很容易想到树链剖分(或者树上差分),蒟蒻不会树上差分,于是就打了个暴力树剖上去。这个树剖操作只有建立和路径修改。
对于每一条指令,将树上起始点到结束点路径上的节点都加1。
这位大佬用的是树上差分,也可以学一学,代码比树剖更加简洁。
传送门:(https://blog.csdn.net/ModestCoder_/article/details/81347876)
再关注一下需要输出的答案:受到压力最大的储间,那么我们在进行修改的时候,构建一个区间最大值的线段树即可。
Code:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAX 500000
using namespace std;
struct Front_Link_Star{
int next,to;
}edge[MAX];
int tree[MAX << 2],lazy[MAX << 2],head[MAX],id[MAX],father[MAX];
int son[MAX],top[MAX],depth[MAX],size[MAX],cnt,dfn,ans,n,m;
inline void Add_Edge(int u,int v){
edge[++cnt].to=v;
edge[cnt].next=head[u];
head[u]=cnt;
}
inline int read(){
int s=0,w=1;
char ch=getchar();
while (!isdigit(ch)){if (ch=='-')w=-1;ch=getchar();}
while (isdigit(ch)){s=(s << 3)+(s << 1)+ch-'0';ch=getchar();}
return s*w;
}
inline void push_down(int now){
lazy[now << 1]+=lazy[now];
lazy[now << 1|1]+=lazy[now];
tree[now << 1]+=lazy[now];
tree[now << 1|1]+=lazy[now];
lazy[now]=0;
} //标记下传
inline void update(int now,int tl,int tr,int left,int right){
if (tl>right||tr<left)return;
if (left<=tl&&tr<=right){
++lazy[now];
++tree[now];
push_down(now);
return;
}
if (lazy[now])push_down(now);
int mid=(tl+tr) >> 1;
update(now << 1,tl,mid,left,right);
update(now << 1|1,mid+1,tr,left,right);
tree[now]=max(tree[now << 1],tree[now << 1|1]);
} //线段树
inline void Modify_Range(int x,int y){
while (top[x]!=top[y]){
if (depth[top[x]]<depth[top[y]])swap(x,y);
update(1,1,n,id[top[x]],id[x]);
x=father[top[x]];
}
if (depth[x]>depth[y])swap(x,y);
update(1,1,n,id[x],id[y]);
}
inline void DFS1(int now,int fa,int d){
father[now]=fa;
depth[now]=d;
size[now]=1;
int maxson=-1;
for (register int i=head[now];i;i=edge[i].next){
int v=edge[i].to;
if (v==fa)continue;
DFS1(v,now,d+1);
size[now]+=size[v];
if (size[v]>maxson){
maxson=size[v];
son[now]=v;
}
}
}
inline void DFS2(int now,int top_heavy){
top[now]=top_heavy;
id[now]=++dfn;
if (!son[now])return;
DFS2(son[now],top_heavy);
for (register int i=head[now];i;i=edge[i].next){
int v=edge[i].to;
if (v!=father[now]&&v!=son[now])DFS2(v,v);
}
} //树链剖分基本操作
int main(){
n=read();m=read();
for (register int i=1;i<=n-1;i++){
int x=read(),y=read();
Add_Edge(x,y);
Add_Edge(y,x);
}
DFS1(1,0,1);
DFS2(1,1);
while (m--){
int x=read(),y=read();
Modify_Range(x,y); //路径修改
}
printf("%d",tree[1]);
return 0;
}