ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LGP5203题解

2022-08-11 16:30:19  阅读:96  来源: 互联网

标签:const int 题解 top LGP5203 son return inline


这个去重给写麻了。。。。。。

显然对于两条非树边,其只能组成最多一条回路。构造方式是将两条非树边在树上的路径中重复的部分去掉,再加上两条非树边即可。

于是考虑如何统计重合的路径。

考虑将一条链拆成两条从祖先到孙子的链。统计这些链相交的情况。

可以注意到只有一个情况会算重:LCA 相同,且对于两组链而言,左边部分的链和右边部分的链均有重合。

即 \(u,v\) 的祖先中深度大于 \(LCA(u,v)\) 中最深的一对祖先,若两条链的这玩意儿相同会被算重。

直接求出这两个祖先然后丢到 map 里面就行了。

考虑一堆祖先到孙子的链如何统计重合情况。

对深度开一个桶,对于 \(u\),树状数组上有值的位置表示有 \(CB[x]\) 条链满足,深的那个节点与 \(u\) 的 LCA 的深度为 \(x\),且浅的那个节点是 \(u\) 的祖先。

做起来很简单,只需要回溯之后将这个深度的桶的值移动到父亲即可。由于需要查询区间和所以使用树状数组

但是注意到,如果存在 \((u1,v1),(u2,v2)\) (二元组中后者为前者的祖先)满足 \(v2\) 是 \(v1\) 的祖先且 \(v1\) 是 \(u2\) 的祖先会被算两遍,需要去掉这种情况。

这种情况再对深度开一个桶,仍然使用树状数组维护即可。

复杂度 \(O(n\log n)\)。

#include<cstdio>
#include<cctype>
#include<vector>
#include<map>
const int M=2e5+5;
int n,m,ege,dfc,s[M],a[M],b[M],L[M],R[M],h[M],u[M],v[M];int f[M],d[M],siz[M],top[M],son[M];long long ans;
std::map<long long,int>CB;std::vector<int>q[M];int BIT[M],V[M];
struct Edge{
	int v,nx;
}e[M<<1];
inline void Add(const int&u,const int&v){
	e[++ege]=(Edge){v,h[u]};h[u]=ege;
	e[++ege]=(Edge){u,h[v]};h[v]=ege;
}
inline void DFS1(const int&u){
	siz[u]=1;d[u]=d[f[u]]+1;
	for(int v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])f[v]=u,DFS1(v),siz[u]+=siz[v],siz[v]>siz[son[u]]&&(son[u]=v);
}
inline void DFS2(const int&u,const int&tp){
	top[u]=tp;L[u]=++dfc;if(!son[u])return void(R[u]=dfc);DFS2(son[u],tp);
	for(int E=h[u];E;E=e[E].nx)if(e[E].v^f[u]&&e[E].v^son[u])DFS2(e[E].v,e[E].v);R[u]=dfc;
}
inline int LCA(int u,int v){
	while(top[u]^top[v])d[top[u]]>d[top[v]]?u=f[top[u]]:v=f[top[v]];return d[u]>d[v]?v:u;
}
inline int Find(int u,const int&v){
	while(top[u]^top[v]){
		if(f[top[u]]==v)return top[u];u=f[top[u]];
	}
	return son[v];
}
inline int read(){
	int n(0);char s;while(!isdigit(s=getchar()));while(n=n*10+(s&15),isdigit(s=getchar()));return n;
}
inline void Mdf(int x,const int&V){
	if(!x)return;::V[x]+=V;while(x<=n)BIT[x]+=V,x+=x&-x;
}
inline int Qry(int x){
	int ans(0);while(x>=1)ans+=BIT[x],x-=x&-x;return ans;
}
inline void DFSX(const int&u){
	Mdf(d[u],b[u]);for(int v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])DFSX(v);
	for(int&x:q[u])ans+=Qry(d[u])-Qry(x)-1;Mdf(d[u]-1,a[u]);Mdf(d[u]-1,V[d[u]]);Mdf(d[u],-V[d[u]]);
}
inline void DFSY(const int&u){
	Mdf(d[u],b[u]);for(int v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])DFSY(v);
	for(int&x:q[u])ans-=Qry(d[u])-Qry(x)-1;Mdf(d[u],-b[u]);
}
inline void swap(int&a,int&b){
	int c=a;a=b;b=c;
}
signed main(){
	n=read();m=read()-n+1;for(int u,v,i=1;i<n;++i)u=read(),v=read(),Add(u,v);
	for(int i=1;i<=m;++i)u[i]=read(),v[i]=read();DFS1(1);DFS2(1,1);
	for(int i=1;i<=m;++i){
		const int&lca=LCA(u[i],v[i]);if(L[u[i]]<L[v[i]])swap(u[i],v[i]);
		if(L[v[i]]<=L[u[i]]&&R[u[i]]<=R[v[i]]){
			--a[Find(u[i],v[i])];++b[u[i]];q[u[i]].push_back(d[v[i]]);++s[u[i]];continue;
		}
		const int&x=Find(u[i],lca),&y=Find(v[i],lca);ans-=CB[(n+1ll)*x+y];++CB[(n+1ll)*x+y];++CB[(n+1ll)*y+x];
		--a[x];--a[y];++b[u[i]];++b[v[i]];q[u[i]].push_back(d[lca]);q[v[i]].push_back(d[lca]);++s[u[i]];++s[v[i]];
	}
	DFSX(1);DFSY(1);for(int i=1;i<=n;++i)ans+=s[i]*(s[i]-1ll)/2;printf("%lld",ans);
}

标签:const,int,题解,top,LGP5203,son,return,inline
来源: https://www.cnblogs.com/lmpp/p/16576492.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有