[cf1486F]Pairs of Paths
以1为根建树,先将所有路径挂在lca上,再分两类讨论:
1.lca相同,此时我们仅关心于lca上不经过第$a$和$b$个儿子路径数,容斥一下,即所有路径-经过$a$的-经过$b$的+经过$a$和$b$的,前三个很容易统计,最后一个用map即可
(这样分类主要是避免lca相同时重复计数)
2.lca不同,考虑其中lca深度较小的路径,将这条路径分为不包含lca的两段,那么另外一条路径的lca一定恰好在其中一条路径上
更具体的,由于两段对称,仅考虑其中一段,如果暴力统计,也就是枚举这段上的每一个节点,假设先枚举的路径是第$a$个儿子,也就是求该点上所有路径-经过$a$的路径
(特别的,对于叶子要将所有以该点为lca的路径全部累计)
不难发现这件事情可以差分,即对于每一个点,记录”其到根路径通过上述方法得出的答案“,转移通过父亲求出,之后差分即可
由于求lca还需要倍增,然后还有map,总复杂度为$o(n\log n)$
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 300005 4 #define mp make_pair 5 struct Edge{ 6 int nex,to; 7 }edge[N<<1]; 8 struct path{ 9 int x,y,x0,y0; 10 }a[N]; 11 vector<int>v[N]; 12 map<int,int>mat[N]; 13 int E,n,m,x,y,head[N],dep[N],id[N],sum[N],dp[N],f[N][21]; 14 long long ans; 15 void add(int x,int y){ 16 edge[E].nex=head[x]; 17 edge[E].to=y; 18 head[x]=E++; 19 } 20 int lca(int x,int y){ 21 if (dep[x]<dep[y])swap(x,y); 22 for(int i=20;i>=0;i--) 23 if (dep[f[x][i]]>=dep[y])x=f[x][i]; 24 if (x==y)return x; 25 for(int i=20;i>=0;i--) 26 if (f[x][i]!=f[y][i]){ 27 x=f[x][i]; 28 y=f[y][i]; 29 } 30 return f[x][0]; 31 } 32 int get(int x,int y){ 33 if (x==y)return x; 34 for(int i=20;i>=0;i--) 35 if (dep[f[x][i]]>dep[y])x=f[x][i]; 36 return x; 37 } 38 void dfs(int k,int fa,int s){ 39 dep[k]=s; 40 f[k][0]=fa; 41 for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1]; 42 for(int i=head[k];i!=-1;i=edge[i].nex) 43 if (edge[i].to!=fa)dfs(edge[i].to,k,s+1); 44 } 45 void calc(int k,int fa){ 46 id[0]=id[k]=0; 47 for(int i=head[k];i!=-1;i=edge[i].nex) 48 if (edge[i].to!=fa)id[edge[i].to]=++id[0]; 49 for(int i=0;i<v[k].size();i++) 50 if (id[a[v[k][i]].x0]>id[a[v[k][i]].y0]){ 51 swap(a[v[k][i]].x,a[v[k][i]].y); 52 swap(a[v[k][i]].x0,a[v[k][i]].y0); 53 } 54 for(int i=0;i<=id[0];i++){ 55 sum[i]=0; 56 mat[i].clear(); 57 } 58 for(int i=0;i<v[k].size();i++){ 59 sum[id[a[v[k][i]].x0]]++; 60 sum[id[a[v[k][i]].y0]]++; 61 mat[id[a[v[k][i]].x0]][id[a[v[k][i]].y0]]++; 62 } 63 for(int i=0;i<v[k].size();i++) 64 if (!id[a[v[k][i]].x0]){ 65 if (!id[a[v[k][i]].y0])ans+=(int)v[k].size()-1; 66 else ans+=(int)v[k].size()-sum[id[a[v[k][i]].y0]]; 67 } 68 else{ 69 ans+=(int)v[k].size()-sum[id[a[v[k][i]].x0]]-sum[id[a[v[k][i]].y0]]; 70 ans+=mat[id[a[v[k][i]].x0]][id[a[v[k][i]].y0]]; 71 } 72 for(int i=head[k];i!=-1;i=edge[i].nex) 73 if (edge[i].to!=fa)dp[edge[i].to]=dp[k]+(int)v[k].size()-sum[id[edge[i].to]]; 74 for(int i=head[k];i!=-1;i=edge[i].nex) 75 if (edge[i].to!=fa)calc(edge[i].to,k); 76 } 77 int main(){ 78 scanf("%d",&n); 79 memset(head,-1,sizeof(head)); 80 for(int i=1;i<n;i++){ 81 scanf("%d%d",&x,&y); 82 add(x,y); 83 add(y,x); 84 } 85 dfs(1,1,0); 86 scanf("%d",&m); 87 for(int i=1;i<=m;i++){ 88 scanf("%d%d",&a[i].x,&a[i].y); 89 int z=lca(a[i].x,a[i].y); 90 a[i].x0=get(a[i].x,z); 91 a[i].y0=get(a[i].y,z); 92 v[z].push_back(i); 93 } 94 calc(1,0); 95 ans/=2; 96 for(int i=1;i<=m;i++){ 97 int z=lca(a[i].x,a[i].y); 98 if (a[i].x!=z)ans+=dp[a[i].x]-dp[a[i].x0]+(int)v[a[i].x].size(); 99 if (a[i].y!=z)ans+=dp[a[i].y]-dp[a[i].y0]+(int)v[a[i].y].size(); 100 } 101 printf("%lld",ans); 102 }