P8456 「SWTR-8」地地铁铁 做题记录
P8456 「SWTR-8」地地铁铁
Description
给定一张 \(n\) 个点,\(m\) 条边的无向连通图。每条边标有 D 或 d。
定义无序点对 \((x, y)\) 是「铁的」,当且仅当 \(x \neq y\) 且 \(x, y\) 之间存在同时出现 D 和 d 的简单路径。
小 A 深知自由组合定律 DdTt 的重要性,所以他让你对这样的点对计数。
\(2\leq n \leq 4\times 10 ^ 5\),\(n - 1\leq m\leq 10 ^ 6\)。
Solution
下面称 D 为 \(1\),d 为 \(0\)。
首先需要知道点双连通图的一些重要性质: 双连通图性质 - XP3301_Pipi - 博客园
考虑容斥,用 \(\binom n 2\) 减去不合法的。
不合法的点对 \((x,y)\) 一定符合以下三种之一:
- \(x,y\) 之间路径上的边全部为 \(0\);
- \(x,y\) 之间路径上的边全部为 \(1\);
- \(x,y\) 之间只存在全部为 \(0\) 和全部为 \(1\) 的路径。
Part I
考虑 \(x,y\) 之间路径上的边全部为 \(0\) 的点对。
若点双 \(G\) 里面存在 \(1\),那么 \(G\) 内或者经过 \(G\) 的点对都不合法。
我们建出圆方树,删去不合法的方点。对于剩下的每一个连通块,设其圆点个数为 \(c\),则贡献为 \(\binom c 2\)。
\(x,y\) 之间路径上的边全部为 \(1\) 的情况也是类似的。
Part II
考虑 \(x,y\) 之间只存在全部为 \(0\) 和全部为 \(1\) 的路径。
Lemma 1
若 \(x,y\) 属于不同点双,则必定不满足条件。
设 \(x,y\) 间一条全 \(0\) 路径为 \(P_0\),一条全 \(1\) 路径为 \(P_1\)。\(P_0,P_1\) 一定在中间某个割点处相交,在此处交换后面的对应片段可以得到 \(01\) 路径。
Lemma 2
对于一个点双 \(G\),其内部最多有一对满足条件的点对。
设 \(G\) 中存在两对点对 \((u,v),(x,y)\) 满足条件。
两个点对有一个公用点。设 \(v=y\)。
任取 \((u,v),(x,y)\) 间两条不同色的纯色路径拼成的环,设为 \(P,Q\)。
删去 \(y\) 点后,\(P,Q\) 之间必定仍然联通,也就是存在一条连接它们的路径。
如图,可以通过它得到一条标为黑色的 \(01\) 路径。
两个点对间没有公用点。
那么 \(P,Q\) 之间一定存在两条连接它们的路径,也可以通过他们得到一条黑色的 \(01\) 路径:
Lemma 3
对于一个满足条件的点对 \((x,y)\),把 \(x,y\) 之间被 \(0\) 路径覆盖的点加入集合 \(S_0\) 中,把 \(x,y\) 之间被 \(1\) 路径覆盖的点加入集合 \(S_1\) 中。设点的全集为 \(S\)。
-
\(S_0\cap S_1=\{x,y\}\),且 \(S_0,S_1\) 之间无边。
设 \(u\in(S_0\cap S_1)\) 且 \(u\ne x,u\ne y\),则存在经过 \(x\) 的 \(01\) 路径。
若 \(S_0,S_1\) 间存在一条边 \(e\),则存在经过 \(e\) 的 \(01\) 路径。
-
\(S_0\cup S_1=S\)。
对于点双内任意一点 \(z\) 满足 \(z\ne x\land z\ne y\),一定存在一条简单路径 \(x\rightarrow z\rightarrow y\),则 \(z\) 一定被某一条同色路径覆盖。
Lemma 4
在点双 \(G\) 内部,存在这样的 \((x,y)\) 的充要条件是 \(G\) 内恰好存在两个点 \(x,y\) 同时有 \(01\) 出边。
先证充分性:拿出四条边 \((x,u_0,0),(x,u_1,1),(v_0,y,0),(v_1,y,1)\)。\(u_0,v_0\) 之间的路径一定全为 \(0\), \(u_1,v_1\) 之间的路径一定全为 \(1\),则 \((x,y)\) 满足条件。
再证必要性:由引理 3 可证。
维护出每个点双内恰好存在两个点 \(x,y\) 同时有 \(01\) 出边的数量即可。
int n,m;
int head[N],tot;
struct Edge{
int to,nxt;
}edge[M];
int dfn[N],low[N],num,tim,fa[N],U[M],V[M],W[M];
int c[N],v0[N],v1[N],w0[N],w1[N];
stack<int> path;
vector<int> e[N],s[N];
void Add(int u,int v){
edge[++tot]={v,head[u]};
head[u]=tot;
}
void Tarjan(int x){
dfn[x]=low[x]=++tim;
path.push(x);
for(int i=head[x];i;i=edge[i].nxt){
int t=edge[i].to;
if(!dfn[t]){
Tarjan(t);
Ckmin(low[x],low[t]);
if(low[t]>=dfn[x]){
num++; int p;
do{
p=path.top(); path.pop();
e[num].push_back(p);
e[p].push_back(num);
}while(p!=t);
e[num].push_back(x);
e[x].push_back(num);
}
}
else Ckmin(low[x],dfn[t]);
}
}
void dfs1(int x,int pr){
fa[x]=pr;
for(int t:e[x]){
if(t==pr) continue;
dfs1(t,x);
}
}
struct DSU{
int fa[N],siz[N];
void Init(){
for(int i=1;i<=num;i++) fa[i]=i;
for(int i=1;i<=num;i++) siz[i]=(i<=n);
}
int Find(int x){
if(fa[x]==x) return x;
return fa[x]=Find(fa[x]);
}
void Merge(int u,int v){
u=Find(u),v=Find(v);
if(u==v) return;
fa[u]=fa[v]; siz[v]+=siz[u];
}
}D;
signed main(){
int S; read(S);
read(n),read(m);
for(int i=1;i<=m;i++){
char w[5];
read(U[i]),read(V[i]);
scanf("%s",w);
W[i]=(w[0]=='D')?1:0;
Add(U[i],V[i]);
Add(V[i],U[i]);
}
num=n; Tarjan(1); dfs1(1,0);
for(int i=1;i<=m;i++){
int u=U[i],v=V[i],id;
if(fa[u]==fa[v]) id=fa[u];
else if(fa[fa[u]]==v) id=fa[u];
else id=fa[v];
s[id].push_back(i);
}
ll ans=1ll*n*(n-1)/2;
for(int i=n+1;i<=num;i++){
for(int j:s[i]){
if(W[j]==0) w0[i]=v0[U[j]]=v0[V[j]]=1;
else w1[i]=v1[U[j]]=v1[V[j]]=1;
}
int cnt=0;
for(int j:e[i]){
if(v0[j]&&v1[j])
cnt++;
v0[j]=v1[j]=0;
}
if(cnt==2) ans--;
}
D.Init();
for(int x=1;x<=num;x++){
for(int t:e[x]){
if(!w0[x]&&!w0[t])
D.Merge(x,t);
}
}
for(int i=1;i<=num;i++){
if(D.Find(i)==i)
ans-=1ll*D.siz[i]*(D.siz[i]-1)/2;
}
D.Init();
for(int x=1;x<=num;x++){
for(int t:e[x]){
if(!w1[x]&&!w1[t])
D.Merge(x,t);
}
}
for(int i=1;i<=num;i++){
if(D.Find(i)==i)
ans-=1ll*D.siz[i]*(D.siz[i]-1)/2;
}
printf("%lld\n",ans);
return 0;
}



浙公网安备 33010602011771号