传送门

分析

首先我们知道如果在一棵树上加一条边一定会构成一个环,而删掉环上任意一条边都不改变连通性。我们把这一性质扩展到这个题上不难发现如果一条树边不在任意一个新边构成的环里则删掉这条边之后可以删掉任意一条新边,对方案数的贡献是m。而如果它只在一个新边构成的环中则要删除这条边和对应的新边,对方案数的贡献是1。而如果它在至少两个新边构成的环中则无论如何也不能将图分成两半,所以对方案数的贡献为0。在知道这些之后我们考虑如何维护一条边在几个由新边构成的环中,那我们自然考虑到了LCA,对于每一条新边将其LCA路径上的边的值都加1.所以我们只需要维护这个值就行了。据说可以用倍增+差分维护,但我并不会,我是用树剖维护的。我们考虑对于原来的树,除根节点外的每一个点入度一定为1,所以我们不在边上累加答案,而用这条边连接的两个点中深度较深的点来代表这条边,最后用2~n这几个点上的值便可以求出方案数。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int LOG = ;
vector<int>v[];
int ans,id[],col[],n,m;
int son[],siz[],cnt,dep[],fa[],acc[];
inline void dfs(int x,int la){
int maxn=;siz[x]=;
for(int i=;i<v[x].size();i++)
if(v[x][i]!=la){
fa[v[x][i]]=x;
dep[v[x][i]]=dep[x]+;
dfs(v[x][i],x);
siz[x]+=siz[v[x][i]];
if(siz[v[x][i]]>maxn){
maxn=siz[v[x][i]];
son[x]=v[x][i];
}
}
return;
}
inline void dfs2(int x,int ac){
id[x]=++cnt;
acc[x]=ac;
if(!son[x])return;
dfs2(son[x],ac);
for(int i=;i<v[x].size();i++)
if(v[x][i]!=fa[x]&&v[x][i]!=son[x])
dfs2(v[x][i],v[x][i]);
return;
}
inline void update(int le,int ri,int wh,int x,int y,int k){
if(x>y)return;
if(le>=x&&ri<=y){
col[wh]+=k;
return;
}
int mid=(le+ri)>>;
if(col[wh]){
col[wh<<]+=col[wh];
col[wh<<|]+=col[wh];
col[wh]=;
}
if(mid>=x)update(le,mid,wh<<,x,y,k);
if(mid<y)update(mid+,ri,wh<<|,x,y,k);
return;
}
inline int q(int le,int ri,int wh,int pl){
if(le==ri)return col[wh];
int mid=(le+ri)>>,ans;
if(col[wh]){
col[wh<<]+=col[wh];
col[wh<<|]+=col[wh];
col[wh]=;
}
if(mid>=pl)ans=q(le,mid,wh<<,pl);
else ans=q(mid+,ri,wh<<|,pl);
return ans;
}
inline void solve(int x,int y){
while(acc[x]!=acc[y]){
if(dep[acc[x]]<dep[acc[y]])swap(x,y);
update(,n,,id[acc[x]],id[x],);
x=fa[acc[x]];
}
if(id[x]>id[y])swap(x,y);
update(,n,,id[x]+,id[y],);
return;
}
int main(){
int i,j,k;
scanf("%d%d",&n,&m);
for(i=;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
v[x].push_back(y);
v[y].push_back(x);
}
fa[]=,dep[]=;
dfs(,);
dfs2(,);
for(i=;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
solve(x,y);
}
for(i=;i<=n;i++){
int x=q(,n,,id[i]);
if(x==)ans+=m;
else if(x==)ans+=;
}
printf("%d\n",ans);
return ;
}

loj10131 暗的连锁的更多相关文章

  1. LOJ10131暗的连锁

    题目描述 原题来自:POJ 3417 Dark 是一张无向图,图中有 N 个节点和两类边,一类边被称为主要边,而另一类被称为附加边.Dark 有 N–1 条主要边,并且 Dark 的任意两个节点之间都 ...

  2. LOJ #10131 「一本通 4.4 例 2」暗的连锁

    LOJ #10131 「一本通 4.4 例 2」暗的连锁 给一棵 \(n\) 个点的树加上 \(m\) 条非树边 , 现在需要断开一条树边和一条非树边使得图不连通 , 求方案数 . $n \le 10 ...

  3. LOJ10131. 「一本通 4.4 例 2」暗的连锁【树上差分】

    LINK solution 很简单的题 你就考虑实际上是对每一个边求出两端节点分别在两个子树里面的附加边的数量 然后这个值是0第二次随便切有m种方案,如果这个值是1第二次只有一种方案 如果这个值是2或 ...

  4. 倍增法求lca:暗的连锁

    https://loj.ac/problem/10131 #include<bits/stdc++.h> using namespace std; struct node{ int to, ...

  5. LOJ P10131 暗的连锁 题解

    每日一题 day27 打卡 Analysis 对于每条非树边 , 覆盖 x 到 LCA 和 y到 LCA 的边 , 即差分算出每个点和父亲的连边被覆盖了多少次 .被覆盖 0 次的边可以和 m 条非树边 ...

  6. POJ3417 Network暗的连锁 (树上差分)

    树上的边差分,x++,y++,lca(x,y)-=2. m条边可以看做将树上的一部分边覆盖,就用差分,x=1,表示x与fa(x)之间的边被覆盖一次,m次处理后跑一遍dfs统计子树和,每个节点子树和va ...

  7. LuoguP3128 [USACO15DEC]最大流Max Flow (树上差分)

    跟LOJ10131暗的连锁 相似,只是对于\(lca\)节点把它和父亲减一 #include <cstdio> #include <iostream> #include < ...

  8. loj题目总览

    --DavidJing提供技术支持 现将今年7月份之前必须刷完的题目列举 完成度[23/34] [178/250] 第 1 章 贪心算法 √ [11/11] #10000 「一本通 1.1 例 1」活 ...

  9. CSU训练分类

    √√第一部分 基础算法(#10023 除外) 第 1 章 贪心算法 √√#10000 「一本通 1.1 例 1」活动安排 √√#10001 「一本通 1.1 例 2」种树 √√#10002 「一本通 ...

随机推荐

  1. KVM- 日常管理与配置

    KVM虚拟机的管理主要是通过virsh命令对虚拟机进行管理. 1.  查看KVM虚拟机配置文件及运行状态 (1) KVM虚拟机默认配置文件位置: /etc/libvirt/qemu/ autostar ...

  2. UVA - 11768 Lattice Point or Not (扩展欧几里得)

    求一条线段上有多少个整点. 是道扩欧基础题,列出两点式方程,然后分四种情况讨论即可.但细节处理较多很容易写挫(某zzWA了十几发才过掉的). 由于数据精度较小,浮点数比较没有用eps,直接==比较了. ...

  3. HttpServletRequest获取请求得URL信息

    request对象中包含的是请求信息,当我们在浏览器地址栏上输入:http://localhost:8080/Example/AServlet?username=zhangsan,这段地址也会作为请求 ...

  4. C# Message 消息处理

    一.消息概述 Windows下应用程序的执行是通过消息驱动的.消息是整个应用程序的工作引擎,我们需要理解掌握我们使用的编程语言是如何封装消息的原理.C#自定义消息通信往往采用事件驱动的方式实现,但有时 ...

  5. 【转】Java内存与垃圾回收调优

    要了解Java垃圾收集机制,先理解JVM内存模式是非常重要的.今天我们将会了解JVM内存的各个部分.如何监控以及垃圾收集调优. Java(JVM)内存模型 正如你从上面的图片看到的,JVM内存被分成多 ...

  6. 记一次内存溢出的分析经历——使用thrift

    背景: 有一个项目做一个系统,分客户端和服务端,客户端用c++写的,用来收集信息然后传给服务端(客户端的数量还是比较多的,正常的有几千个), 服务端用Java写的(带管理页面),属于RPC模式,中间的 ...

  7. Makefile中的路径

    使用 $(shell pwd) 可以在Makefile中指定为当前Makefile所在目录的路径

  8. Azure RBAC管理ASM资源

    上一篇文章介绍了Azure基于ARM的RBAC,给不同的用户分配不同的权限. 但目前在国内使用的大部分用户还是以ASM的资源为主.比如:VM.Storage.Network.WebAPP.SQL Az ...

  9. Linux评估 CPU使用情况

    评价参数 1)CPU utilization:最直观最重要的就是CPU的使用率.如果长期超过80%,则表明CPU遇到了瓶颈:2)User time: 用户进程使用的CPU:该数值越高越好,表明越多的C ...

  10. Linux应用函数 -- 字符串

    1.strchr 原型 char *strchr(const char* _Str,char _Val) 头文件 string.h 功能 查找字符串_Str中首次出现字符_Val的位置 返回值  成功 ...