agc033F Adding Edges
- 给你一棵
N
N
N 个点的树
T
T
T 和一个
M
M
M条边的无向图
G
G
G,对于
G
G
G进行如下加边操作直到无法操作:
- 选择
a
,
b
,
c
a,b,c
a,b,c使得
a
,
b
,
c
a,b,c
a,b,c以某种顺序在
T
T
T的一条链上,并且存在边
(
a
,
b
)
,
(
a
,
c
)
(a,b),(a,c)
(a,b),(a,c)。
- 将
(
b
,
c
)
(b,c)
(b,c)加入
G
G
G。
- 问最后
G
G
G中有多少边。
-
N
,
M
≤
2000
N,M\le2000
N,M≤2000
Solution
- 有一种很妙的转化,如果链上点的顺序为
(
a
,
b
,
c
)
(a,b,c)
(a,b,c),存在
(
a
,
b
)
,
(
b
,
c
)
(a,b),(b,c)
(a,b),(b,c),那么这是很好做的,只需要从每一点开始dfs即可知道每一个点的连边。
- 那么如果对于链上顺序的
(
a
,
b
,
c
)
(a,b,c)
(a,b,c),存在
(
a
,
b
)
,
(
a
,
c
)
(a,b),(a,c)
(a,b),(a,c),我们不妨将
(
a
,
c
)
(a,c)
(a,c)换成
(
b
,
c
)
(b,c)
(b,c)。
- 记录
f
[
x
]
[
y
]
f[x][y]
f[x][y]表示如果有一条边为
(
x
,
y
)
(x,y)
(x,y),不妨将它缩短为
(
f
[
x
]
[
y
]
,
y
)
(f[x][y],y)
(f[x][y],y)。
- 新加入一条边就将它缩到最短,然后再考虑加进去后对于那些已经在图里面的边有影响,以
x
x
x和
y
y
y为根dfs即可。然后再不断新加入边。
- 由于每一个
f
[
x
]
[
y
]
f[x][y]
f[x][y]只需要被覆盖一次,所以时空复杂度是
O
(
n
2
+
n
m
)
O(n^2+nm)
O(n2+nm)的。
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#define maxn 2005
using namespace std;
int n,m,i,j,k,f[maxn][maxn],g[maxn][maxn];
int t,w,d[maxn*maxn][2],vis[maxn][maxn];
int em,e[maxn*2],nx[maxn*2],ls[maxn],dep[maxn][maxn];
void insert(int x,int y){
em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
em++; e[em]=x; nx[em]=ls[y]; ls[y]=em;
}
void dfs(int x,int p,int st){
dep[st][x]=dep[st][p]+1;
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
dfs(e[i],x,st);
}
void cover(int x,int p,int st,int v){
f[st][x]=v;
if (g[st][x]){
if (!vis[x][v])
w++,d[w][0]=v,d[w][1]=x,vis[x][v]=vis[v][x]=1;
}
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
cover(e[i],x,st,v);
}
void doit(int x,int y){
g[x][y]=1;
for(int i=ls[y];i;i=nx[i]) if (dep[x][e[i]]>dep[x][y])
cover(e[i],y,x,y);
}
int tot,dfn[maxn],sz[maxn],cnt,E[maxn][2];
void getdfn(int x,int p){
dfn[x]=++tot,sz[x]=1;
for(int i=ls[x];i;i=nx[i]) if (e[i]!=p)
getdfn(e[i],x),sz[x]+=sz[e[i]];
}
int fa[maxn];
int father(int x){return (fa[x]==x)?x:fa[x]=father(fa[x]);}
void link(int x,int y){
if (father(x)!=father(y))
fa[fa[x]]=fa[y];
}
int main(){
freopen("ceshi.in","r",stdin);
scanf("%d%d",&n,&m);
for(i=1;i<n;i++) scanf("%d%d",&j,&k),insert(j,k);
for(i=1;i<=n;i++) dfs(i,0,i);
while (m--){
int x,y; scanf("%d%d",&x,&y);
if (!vis[x][y]) w++,d[w][0]=x,d[w][1]=y,vis[x][y]=vis[y][x]=1;
while (t<w){
t++,x=d[t][0],y=d[t][1];
while (f[x][y]) x=f[x][y];
while (f[y][x]) y=f[y][x];
if (!g[x][y]) doit(x,y);
if (!g[y][x]) doit(y,x);
}
}
for(i=1;i<=n;i++) for(j=i+1;j<=n;j++)
if (g[i][j]&&!f[i][j]&&!f[j][i])
cnt++,E[cnt][0]=i,E[cnt][1]=j;
int ans=0;
for(int st=1;st<=n;st++){
tot=0,memset(dfn,0,sizeof(dfn));
getdfn(st,0);
for(i=1;i<=n;i++) fa[i]=i;
for(i=1;i<=cnt;i++) {
if (dfn[E[i][0]]>dfn[E[i][1]]) swap(E[i][0],E[i][1]);
if (dfn[E[i][1]]>=dfn[E[i][0]]&&dfn[E[i][1]]<dfn[E[i][0]]+sz[E[i][0]])
link(E[i][0],E[i][1]);
}
for(i=1;i<=n;i++) if (father(i)==father(st)&&i!=st)
ans++;
}
printf("%d",ans/2);
}