其他分享
首页 > 其他分享> > LGP5203题解

LGP5203题解

作者:互联网

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

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

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

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

可以注意到只有一个情况会算重: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