【2020模拟赛day9】A. 砍苹果树
很经典的一道题目,首先我们考虑每一条附加边x-y 会造成的影响
会使得x-y的简单路径上每条边断开的权值都加1
权值的意义:权值为0,它搭配m条附加边的任意一个都可以
权值为1,它只能搭配一个附加边
权值大于1,无论搭配哪个附加边,都无法做到使原图不连通
所以我们利用树上差分,处理每条附加边时,先把它加到一个差分数组d中 (这里把边权记在点上,每个点上的值为它和他父亲的连边)
当所有的附加边处理完之后,跑一边dfs累加一下就好了
代码
#include<bits/stdc++.h> using namespace std; const int maxn=3e5+5; int n,m,head[maxn],cnt,dep[maxn]; int f[maxn][20],d[maxn]; struct edge { int to,nxt; }e[maxn<<1]; void add(int x,int y) { e[++cnt].to=y; e[cnt].nxt=head[x]; head[x]=cnt; } void dfs(int u,int fa) { dep[u]=dep[fa]+1; f[u][0]=fa; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; dfs(to,u); } } void init_lca() { for(int i=1;i<=n;i++) for(int j=1;j<=19;j++) f[i][j]=f[f[i][j-1]][j-1]; } int LCA(int x,int y) { if(dep[x]<dep[y]) swap(x,y); for(int i=19;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i]; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void calc(int u,int fa) { for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa) continue; dfs(to,u); d[u]+=d[to]; } } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d%d",&n,&m); int x,y; for(int i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } dfs(1,0); init_lca(); for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); int lca=LCA(x,y); d[x]++; d[y]++; d[lca]-=2; } calc(1,0); long long ans=0; for(int i=2;i<=n;i++) { if(!d[i]) ans+=m; if(d[i]==1) ans+=1; } printf("%lld\n",ans); return 0; }