【LGR114C】地地铁铁

题意:

给定 n n n 个点 m m m 条边的无向连通图,每条边标有 0 0 0 1 1 1,统计无序点对 ( x , y ) (x,y) (x,y) 的数量,满足 x , y x,y x,y 之间存在一条简单路径(点不重),使得这条简单路径既经过 0 0 0 边也经过 1 1 1 边。

n ≤ 4 × 1 0 5 n\leq 4\times 10^5 n4×105 m ≤ 1 0 6 m\leq 10^6 m106

题解:

首先变为统计 ( x , y ) (x,y) (x,y) 之间任意简单路径都只经过 0 0 0 边或只经过 1 1 1 边的 ( x , y ) (x,y) (x,y) 的对数。

分类讨论,考虑 ( x , y ) (x,y) (x,y) 之间所有简单路径都只经过 0 0 0 边的点对数量。

借着这个机会,系统总结一下几个点双的基本性质。接下来我们称 “非平凡点双” 为点数 ≥ 3 \geq 3 3 的点双。

  • 引理 1:对于非平凡点双 S S S 和任意 S S S 内两个不同的点 a , b a,b a,b,存在两条 a , b a,b a,b 间的点不交(除 a , b a,b a,b 外,以后将不再说明此事)的简单路径 A , B A,B A,B

    注意点双的定义是:删掉任意一个点后原图仍连通。所以这个引理不是废话(

    证明:考虑对 a , b a,b a,b 间的最短路 d ( a , b ) d(a,b) d(a,b) 归纳证明。

    d ( a , b ) = 1 d(a,b)=1 d(a,b)=1 即存在边 ( a , b ) (a,b) (a,b) 时。若不存在另外一条 a , b a,b a,b 间的路径,那么删掉边 ( a , b ) (a,b) (a,b) a , b a,b a,b 将不连通,不妨设此时 a a a 所在的连通块大小 ≥ 2 \geq 2 2,那么在原图中删掉 a a a 将会导致原图不连通,矛盾。

    d ( a , b ) > 1 d(a,b)>1 d(a,b)>1 时。考虑 a , b a,b a,b 间的任意一条最短路 a − ⋯ − c − b a-\cdots-c-b acb。根据假设,存在两条 a , c a,c a,c 间的点不交简单路径 A , B A,B A,B。根据定义,删去 c c c a , b a,b a,b 仍然连通,此时取一条 a , b a,b a,b 间的简单路径 P P P,那么 P P P 不经过 c c c。如图:

    在这里插入图片描述

    不妨设 P P P A , B A,B A,B 第一次相交在 B B B 上的点 d d d,那么 b → P d → B a b\xrightarrow{P}d\xrightarrow{B}a bP dB a b → c → A a b\rightarrow c\xrightarrow{A}a bcA a 即为两条点不交的所求路径。

  • 推论 2:对于点数 ≥ 3 \geq 3 3 的图 G G G G G G 是点双连通分量当且仅当对于任意 G G G 中的两个不同的点 a , b a,b a,b,存在两条 a , b a,b a,b 间的点不交的简单路径 A , B A,B A,B

  • 引理 3:对于点双 S S S 和任意 S S S 内三个不同的点 a , b , c a,b,c a,b,c(这蕴含 S S S 是非平凡的),存在一条简单路径依次经过 a , b , c a,b,c a,b,c

    证明:如图,任取两条 a , b a,b a,b 间的点不交的简单路径 A , B A,B A,B,再任取一条 b , c b,c b,c 间的且不经过 a a a 的路径 P P P,根据点双的定义,这三条路径都是可以取得到的。

    在这里插入图片描述

    不妨设 P P P A , B A,B A,B 最后一次相交在 B B B 上的点 d d d(那么 d ≠ a d\neq a d=a),于是 a → A b → B d → P c a\xrightarrow{A}b\xrightarrow{B}d\xrightarrow{P}c aA bB dP c 即为一条所求路径。

  • 引理 4:对于非平凡点双 S S S 和任意 S S S 内的一点 u u u 和一边 e e e,存在一个经过 u , e u,e u,e 的简单环。

    证明:设 e = ( a , b ) e=(a,b) e=(a,b)。若 u = a u=a u=a u = b u=b u=b 则显然;否则,根据引理 3,存在一条简单路径 P P P 依次经过 a , u , b a,u,b a,u,b,显然 P P P 不经过 e e e,于是 P , e P,e P,e 组成的简单环即为一条所求的环。

  • 引理 5:对于点双 S S S 和任意 S S S 内两个不同的点 a , b a,b a,b 和一边 e e e,存在一条 a , b a,b a,b 间的简单路径经过 e e e

    证明:若 S S S 中只有两个点的情况那么证明显然,所以不妨设 S S S 是非平凡点双。

    e = ( u , v ) e=(u,v) e=(u,v)。根据引理 4,存在一个经过 a , e a,e a,e 的简单环 C C C,不妨将 C C C a − u a-u au 段称为 A A A a − v a-v av 段称为 B B B。如图:

    在这里插入图片描述

    任取一条从 b b b 出发不经过 a a a 的与 C C C 相交的简单路径 P P P(为什么一定能取到?考虑取一条 b , u b,u b,u 间的不经过 a a a 的简单路径即可)

    不妨设 P P P C C C 第一次相交在 A A A 上的点 c c c(那么 c ≠ a c\neq a c=a),于是 b → P c → A u → e v → B a b\xrightarrow{P}c\xrightarrow{A}u\xrightarrow{e}v\xrightarrow{B}a bP cA ue vB a 即为一条所求路径。

引理 3 和引理 5 是两个很常用的结论。

看回这题,考虑将原图缩成点双,那么若 x , y x,y x,y 间存在某个有 1 1 1 边的点双,那么根据引理 5, x , y x,y x,y 间就一定有经过 1 1 1 边的简单路径。反之,若 x , y x,y x,y 间所有点双都只有 0 0 0 边,那么 x , y x,y x,y 间的所有简单路径肯定都只包含 0 0 0 边。

有了这个结论后剩下就好做了。具体地,先建出圆方树。然后对于原图上一条 0 0 0 ( u , v ) (u,v) (u,v),它恰属于一个点双 S S S,找到 S S S 对应的方点只需在圆方树上根据 u , v u,v u,v 相对位置讨论即可,然后我们再给该方点打上标记。接下来统计圆方树上不经过标记点的圆点间路径数即可。

于是我们解决了 “ ( x , y ) (x,y) (x,y) 之间所有简单路径都只经过 0 0 0 边的点对数量”,对于只经过 1 1 1 边的同理统计。

接下来统计 ( x , y ) (x,y) (x,y) 之间既有只经过 0 0 0 边的路径(称为 0 0 0 路)、又有只经过 1 1 1 边的路径(称为 1 1 1 路)的点对数量,称这种点对为 “合法点对”。

  • 命题 6:若 ( x , y ) (x,y) (x,y) 为合法点对,那么 x , y x,y x,y 之间的任意一条 0 0 0 路和任意一条 1 1 1 路都不交(除 x , y x,y x,y 外)。

    证明:否则可以调整得到一条 01 01 01 路。

  • 推论 7:若 ( x , y ) (x,y) (x,y) 为合法点对,那么 x , y x,y x,y 肯定同在一个点双 S S S 内,进一步地, S S S 肯定是非平凡点双。

考虑对某个非平凡点双 S S S 统计其内的合法点对 ( x , y ) (x,y) (x,y) 的数量。

一个直觉(出题人说有,但我没有,怎么会事呢?)是,点双 S S S 肯定长成这样:

在这里插入图片描述

接下来我们来证明这一点。

我们称 S S S 内的一点 u u u 为交错点,当且仅当 u u u S S S 内既存在相邻的 0 0 0 边,也存在相邻的 1 1 1 边。

  • 命题 8:若 ( x , y ) (x,y) (x,y) S S S 内的合法点对。对于 S S S 内的任意交错点 u u u x , y x,y x,y 中必有一者等于 u u u

    证明:反证,若 x , y , u x,y,u x,y,u 为三个不同的点。设与 u u u 相邻的 0 0 0 边为 ( u , a ) (u,a) (u,a),与 u u u 相邻的 1 1 1 边为 ( u , b ) (u,b) (u,b)。根据引理 5,存在两条 x , y x,y x,y 间简单路径,其中一条 A A A 经过 ( u , a ) (u,a) (u,a),其中一条 B B B 经过 ( u , b ) (u,b) (u,b)。如图:

    在这里插入图片描述

    由于 ( x , y ) (x,y) (x,y) 为合法点对,那么可知 A A A 0 0 0 路且 B B B 1 1 1 路,但它们相交在点 u u u,根据命题 6 可知矛盾。

  • 推论 9:若 S S S 内存在合法点对,则 S S S 内至多有 2 2 2 个交错点。

  • 推论 10:若 S S S 内存在合法点对,则 S S S 内恰有 2 2 2 个交错点。

    证明:若 S S S 只有一个交错点,容易证明该交错点是割点,矛盾。

  • 命题 11:若 S S S 内恰有 2 2 2 个交错点 x , y x,y x,y,那么 S S S 内恰有一对合法点对 ( x , y ) (x,y) (x,y)

    证明:对于任意 S S S 内的合法点对 ( x ′ , y ′ ) (x',y') (x,y),根据命题 8 可知, x ′ , y ′ x',y' x,y 中必有一者等于 x x x,且必有一者等于 y y y,那么 ( x ′ , y ′ ) = ( x , y ) (x',y')=(x,y) (x,y)=(x,y)

    从而只需证明 ( x , y ) (x,y) (x,y) 为合法点对即可:根据引理易知, x , y x,y x,y 之间肯定既有包含 0 0 0 边的路径、也有包含 1 1 1 边的路径,于是只需证明 x , y x,y x,y 间不存在既包含 0 0 0 边也包含 1 1 1 边的路径即可。而若出现了这种路径,显然能找到另一个不同于 x , y x,y x,y 的交错点,矛盾。

于是,我们证明了,某个非平凡点双 S S S 内包含合法点对,当且仅当 S S S 中恰有 2 2 2 个交错点,且此时 S S S 中恰包含一个合法点对。

于是我们可以线性处理整个问题。具体地,对于原图上一条边 ( u , v ) (u,v) (u,v),找到其所在点双在圆方树上对应点 S S S,我们给树上 ( u , S ) , ( v , S ) (u,S),(v,S) (u,S),(v,S) 这两条边分别标上 ( u , v ) (u,v) (u,v) 所属颜色的记号,那么最后若 ( u , S ) (u,S) (u,S) 上既有 0 0 0 记号又有 1 1 1 记号,就意味着 u u u S S S 内的交错点。

ll C2(int x){return 1ll*x*(x-1)/2;}

struct edge
{
	int u,v;
	bool c;
}e[M];

int n,m;
int top,sta[N];
int idx,dfn[N],low[N];
int node,fa[N<<1],dep[N<<1];
int tag[N<<1],tot[N<<1];
ll ans;

vector<int> e1[N],e2[N<<1];

void tarjan(int u)
{
	dfn[u]=low[u]=++idx;
	sta[++top]=u;
	for(int v:e1[u])
	{
		if(!dfn[v])
		{
			tarjan(v);
			low[u]=min(low[u],low[v]);
			if(low[v]>=dfn[u])
			{
				int S=++node,w;
				do
				{
					w=sta[top],top--;
					e2[S].push_back(w),e2[w].push_back(S);
				}while(w!=v);
				e2[S].push_back(u),e2[u].push_back(S);
			}
		}
		else low[u]=min(low[u],dfn[v]);
	}
}

void dfs(int u)
{
	for(int v:e2[u]) if(v!=fa[u])
		fa[v]=u,dep[v]=dep[u]+1,dfs(v);
}

int findS(int u,int v)
{
	return fa[dep[u]<dep[v]?v:u];
}

int dfs1(int u)
{
	int size=(u<=n);
	for(int v:e2[u]) if(v!=fa[u])
		tag[u]?(ans+=C2(dfs1(v))):(size+=dfs1(v));
	return size;
}

void calc1(bool c)
{
	for(int i=1;i<=m;i++)
		if(e[i].c^c) tag[findS(e[i].u,e[i].v)]=1;
	ans+=C2(dfs1(1));
	for(int i=1;i<=node;i++) tag[i]=0;
}

void calc2()
{
	for(int i=1;i<=m;i++)
	{
		int S=findS(e[i].u,e[i].v);
		tag[dep[e[i].u]<dep[S]?S:e[i].u]|=(1<<e[i].c);
		tag[dep[e[i].v]<dep[S]?S:e[i].v]|=(1<<e[i].c);
	}
	for(int i=1;i<=node;i++)
		if(tag[i]==3) tot[i]++,tot[fa[i]]++;
	for(int i=n+1;i<=node;i++)
		if(tot[i]==2) ans++;
}

int main()
{
	read(),n=node=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		e[i].u=read(),e[i].v=read(),e[i].c=(getchar()=='D');
		e1[e[i].u].push_back(e[i].v),e1[e[i].v].push_back(e[i].u);
	}
	tarjan(1);
	dfs(1);
	calc1(0);
	calc1(1);
	calc2();
	printf("%lld\n",C2(n)-ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值