题目:
已知一棵有n个点的树,现加m条边,问:有多少种方案,选一条原树边,一条新加边,使两边删去后图不连通
题解:
乍一看,好像和割点和桥有点像,然而找到桥后就不知道怎么办了。
x->y的新加边:x->lca(x,y),y->lca(x,y)中经过边加一覆盖数
其实统计被新加边覆盖的边和覆盖次数就行了
未被覆盖: 可以与任意新加边组合成合法方案
(
a
n
s
+
=
m
)
(ans+=m)
(ans+=m)
被覆盖一次: 仅可以与此覆盖边组成合法方案
(
a
n
s
+
+
)
(ans++)
(ans++)
被覆盖两次及以上:无效
———————————
大致方法掌握了,暴力加方案被覆盖数吗?
TLE了,QAQ
联想一下,我们每次加一整条路径,额,似乎和区间加有点像
我们想到了线段树维护区间值,额,这样的话,似乎要树剖一下套线段树,我还是洗洗睡吧
其实可以更简单一点,有请今天的主角:
树上差分
其实就是将数列上的操作照搬下来了
修
改
:
左
端
点
+
v
a
l
,
(
右
端
点
+
1
)
−
v
a
l
左
节
点
+
v
a
l
,
右
节
点
+
v
a
l
,
L
C
A
−
2
∗
v
a
l
修改:左端点+val,(右端点+1)-val \\ \ \ \ \ \ \ \ \ \ \ \ \ 左节点+val,右节点+val,LCA-2*val
修改:左端点+val,(右端点+1)−val 左节点+val,右节点+val,LCA−2∗val
求
值
:
前
缀
1
−
>
i
,
表
示
i
上
的
值
前
缀
子
树
,
表
示
该
节
点
的
值
(
当
然
也
可
以
是
当
前
边
)
求值:前缀1->i,表示i上的值\\ \ \ \ \ \ \ \ \ \ \ \ \ 前缀子树,表示该节点的值(当然也可以是当前边)
求值:前缀1−>i,表示i上的值 前缀子树,表示该节点的值(当然也可以是当前边)
额,似乎就没了。。。
#include<cstdio>
#include<iostream>
#include<string.h>
#define ch getchar()
#define ir read()
inline int ir
{
int ans=0;char s=ch;
while(s>'9'||s<'0')s=ch;
while(s>='0'&&s<='9')
{
ans=(ans*10)+(s&15);
s=ch;
}return ans;
}
using namespace std;
const int N=1e5+10,M=5e5+10;
int n,m,ans;
int fa[N],dep[N];
int head[N],nex[M],to[M],tot=1;
void build(int u,int v){tot++;nex[tot]=head[u];to[tot]=v;head[u]=tot;}
int bz[N][25];
void get_bz()
{
for(int k=1;k<=20;k++)
for(int i=1;i<=n;i++)
bz[i][k]=bz[bz[i][k-1]][k-1];
}
int lca(int x,int y)
{
if(dep[x]<dep[y])swap(x,y);
for(int i=20;i>=0;i--)
if(dep[bz[x][i]]>=dep[y])x=bz[x][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
{
if(bz[x][i]!=bz[y][i])
x=bz[x][i],y=bz[y][i];
}return fa[x];
}
void dfs(int u,int f)
{
bz[u][0]=fa[u]=f;
dep[u]=dep[f]+1;
for(int i=head[u];i;i=nex[i])
{
int v=to[i];
if(v==f)continue;
dfs(v,u);
}
}
int num[N];
int dfs(int u,int f)
{
int g=num[u];
for(int i=head[u];i;i=nex[i])
{
int v=to[i];
if(v==f)continue;
g+=dfs(v,u);
}
if(u!=1&&g==0)ans+=m;
else if(g==1)ans++;
return g;
}
int x,y;
int main()
{
n=ir;m=ir;
for(int i=1;i<n;i++)
{
x=ir;y=ir;
build(x,y);build(y,x);
}
dfs(1,0);
get_bz();
for(int i=1;i<=m;i++)
{
x=ir;y=ir;;
num[x]++;num[y]++;
num[lca(x,y)]-=2;
}
dfs(1,0);
printf("%d",ans);
}