2 solutions
-
1
-
图论:
删除环上点 及相关边后,剩余图为森林。其连通块个数满足公式:
-
公式应用:
:环上的点集
:环上点的个数
:环上边的个数,满足
:删除的边数
结合森林公式推导:
-
剩余点数 =
-
剩余边数 = 总边数
-
连通块个数 = $(n - |S|) - [(n-1) - E_{\text{del}}] = E_{\text{del}} - |S| + 1$
进一步推导 :
: 中所有点的度数和。
环上内部边数为 ,每条内部边被 中两点各计数一次,外部边(一端在 )仅计数一次。因此:
-
$\text{sum\_deg}_S = 2 \times \text{内部边数} + \text{外部边数} = 2A + (E_{\text{del}} - A) = A + E_{\text{del}}$
-
代入连通块个数公式:
- $⇒\text{ans} = (\text{sum\_deg}_S - A) - (A + 1) + 1 = \text{sum\_deg}_S - 2A$
-
#include<bits/stdc++.h> using namespace std; #define FAST_IO ios::sync_with_stdio(0),cin.tie(0),cout.tie(0) #define int long long #define MAXN 1000005 #define LOG 25 int n,q; vector<int> g[MAXN]; int dep[MAXN],st[MAXN][LOG]; int deg[MAXN],sum[MAXN]; int lg[MAXN]; void dfs(int u,int pre) { dep[u]=dep[pre]+1; st[u][0]=pre; sum[u]=sum[pre]+deg[u]; for(int i=1;i<=lg[dep[u]];i++) st[u][i]=st[st[u][i-1]][i-1]; for(int v:g[u]) if(v!=pre) dfs(v,u); } int get_lca(int u,int v) { if(dep[u]<dep[v]) swap(u,v); for(int i=lg[dep[u]];i>=0;i--) { if(dep[u]-(1<<i)>=dep[v]) u=st[u][i]; } if(u==v) return u; for(int i=lg[dep[u]];i>=0;i--) { if(st[u][i]!=st[v][i]) u=st[u][i],v=st[v][i]; } return st[u][0]; } signed main() { FAST_IO; //freopen("easy.in","r",stdin); //freopen("easy.out","w",stdout); cin>>n>>q; lg[1]=0;for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1; for(int i=1;i<=n-1;i++) { int x,y; cin>>x>>y; g[x].push_back(y),g[y].push_back(x); deg[x]++,deg[y]++; } dfs(1,0); while(q--) { int u,v; cin>>u>>v; int lca=get_lca(u,v); int deg_sum=sum[u]+sum[v]-2*sum[lca]+deg[lca]; int cnt=dep[u]+dep[v]-2*dep[lca]; int ans=deg_sum-2*cnt; cout<<ans<<'\n'; } return 0; } -
Information
- ID
- 714
- Time
- 4000ms
- Memory
- 1024MiB
- Difficulty
- 10
- Tags
- # Submissions
- 8
- Accepted
- 2
- Uploaded By