题目大意:给定一棵 1~n 标号的树。Tree[L,R]表示最少需要选择的边的数量使得 L~R 号点两两连通。求:

\[\sum_{L=1}^{n} \sum_{R=L}^{n} \operatorname{Tree}[L, R]
\]

题解:

要求的是经过边的数量,可以考虑每条边对答案的贡献。

对于边 (u,v) ,定义一个特征序列 a[1...n],若 i 在以 u 为根的子树中,则 a[i]=1,否则 a[i]=0。发现若要求该边的贡献为 1,则选择的范围 a[l]-a[r] 中必须要既有 0 又有 1,这样才能跨过这条边,到达子树外面的节点。问题转化成了求对于树上每个节点的特征序列来说,既有 0 又有 1 的区间的个数和是多少。但是这个问题并不好求,可以转化为求特征序列中,只有 0 或 1 的区间个数,再用总共的区间个数减掉这些即可。因此,可以采用线段树来维护区间最长前后缀 0/1 的长度,区间合并的时候只需处理左区间的后缀和右区间的前缀即可完成。树上的问题还需要进行线段树合并来完成,时间复杂度为 \(O(nlogn)\)。

代码如下

#include <bits/stdc++.h>
#define pb push_back
using namespace std;
const int maxn=1e5+10;
typedef long long LL; int n; LL ans;
vector<int> G[maxn];
struct node{
#define ls(o) t[o].lc
#define rs(o) t[o].rc
int lc,rc,lmx0,lmx1,rmx0,rmx1;
LL sum0,sum1;
}t[maxn*20];
int tot,rt[maxn];
inline void pushup(int o,int l,int r){
int mid=l+r>>1;
if(!ls(o))t[ls(o)].sum0=(LL)(mid-l+1)*(mid-l+2)/2,t[ls(o)].lmx0=t[ls(o)].rmx0=mid-l+1;
if(!rs(o))t[rs(o)].sum0=(LL)(r-mid)*(r-mid+1)/2,t[rs(o)].lmx0=t[rs(o)].rmx0=r-mid;
t[o].sum0=t[ls(o)].sum0+t[rs(o)].sum0+(LL)t[ls(o)].rmx0*t[rs(o)].lmx0;
t[o].sum1=t[ls(o)].sum1+t[rs(o)].sum1+(LL)t[ls(o)].rmx1*t[rs(o)].lmx1;
t[o].lmx0=t[ls(o)].lmx0==mid-l+1?t[ls(o)].lmx0+t[rs(o)].lmx0:t[ls(o)].lmx0;
t[o].lmx1=t[ls(o)].lmx1==mid-l+1?t[ls(o)].lmx1+t[rs(o)].lmx1:t[ls(o)].lmx1;
t[o].rmx0=t[rs(o)].rmx0==r-mid?t[rs(o)].rmx0+t[ls(o)].rmx0:t[rs(o)].rmx0;
t[o].rmx1=t[rs(o)].rmx1==r-mid?t[rs(o)].rmx1+t[ls(o)].rmx1:t[rs(o)].rmx1;
}
void insert(int &o,int l,int r,int pos){
if(!o)o=++tot;
if(l==r){t[o].lmx1=t[o].rmx1=t[o].sum1=1;return;}
int mid=l+r>>1;
if(pos<=mid)insert(ls(o),l,mid,pos);
else insert(rs(o),mid+1,r,pos);
pushup(o,l,r);
}
int merge(int x,int y,int l,int r){
if(!x||!y)return x+y;
if(l==r)return t[x].sum1?x:y;
int mid=l+r>>1;
ls(x)=merge(ls(x),ls(y),l,mid);
rs(x)=merge(rs(x),rs(y),mid+1,r);
return pushup(x,l,r),x;
}
void dfs(int u,int fa){
for(auto v:G[u]){
if(v==fa)continue;
dfs(v,u);
rt[u]=merge(rt[u],rt[v],1,n);
}
insert(rt[u],1,n,u);
LL ret=(LL)n*(n+1)/2-t[rt[u]].sum0-t[rt[u]].sum1;
if(u!=1)ans+=ret;
} void read_and_parse(){
scanf("%d",&n);
for(int i=1;i<n;i++){
int x,y;
scanf("%d%d",&x,&y);
G[x].pb(y),G[y].pb(x);
}
}
void solve(){
dfs(1,0);
printf("%lld\n",ans);
}
int main(){
read_and_parse();
solve();
return 0;
}

【hiho1715】树的联通问题的更多相关文章

  1. 51 NOD 1325 两棵树的问题

    Discription 对于 100% 的数据, N<=50. solution: 发现N比较小,所以我们可以花O(N^2)的代价枚举两颗树的联通块的LCA分别是哪个点,然后现在问题就变成了:选 ...

  2. P4383 [八省联考2018]林克卡特树 树形dp Wqs二分

    LINK:林克卡特树 作为树形dp 这道题已经属于不容易的级别了. 套上了Wqs二分 (反而更简单了 大雾 容易想到还是对树进行联通情况的dp 然后最后结果总和为各个联通块内的直径. \(f_{i,j ...

  3. 题解西电OJ (Problem 1004 -亚特兰提斯)--最小生成树

    Description 为了找寻沉睡的亚特兰提斯大陆,wm来到了大西洋上进行探险,找了半个月仍一无所获.然而在一次突袭而来的暴风雨后,wm的船莫名地驶入了一片未知的区域,发现了一个地图上未标记的岛屿, ...

  4. NOI前的考试日志

    4.14 网络流专项测试 先看T1,不会,看T2,仙人掌???wtf??弃疗.看T3,貌似最可做了,然后开始刚,刚了30min无果,打了50分暴力,然后接着去看T1,把序列差分了一下,推了会式子,发现 ...

  5. kruskal重构树学习笔记

    \(kruskal\) 重构树学习笔记 前言 \(8102IONCC\) 中考到了,本蒟蒻不会,所以学一下. 前置知识 \(kruskal​\) 求最小(大)生成树,树上求 \(lca​\). 算法详 ...

  6. 2015-2016 ACM-ICPC Northeastern European Regional Contest (NEERC 15)C - Cactus Jubilee

    题意:给一颗仙人掌,要求移动一条边,不能放在原处,移动之后还是一颗仙人掌的方案数(仙人掌:无向图,每条边只在一个环中),等价于先删除一条边,然后加一条边 题解:对于一颗仙人掌,分成两种边,1:环边:环 ...

  7. Qtree4——动态点分治

    题目描述 给出一棵边带权的节点数量为n的树,初始树上所有节点都是白色.有两种操作: C x,改变节点x的颜色,即白变黑,黑变白 A,询问树中最远的两个白色节点的距离,这两个白色节点可以重合(此时距离为 ...

  8. 【洛谷P1122】最大子树和

    题目大意:给定一棵 N 个节点的无根树,点有点权,点权有正有负,求这棵树的联通块的最大权值之和是多少. 题解:设 \(dp[i]\) 表示以 i 为根节点的最大子树和,那么只要子树的 dp 值大于0, ...

  9. 【AC自动机】AC自动机

    Definition & Solution AC自动机是一种多模式串的字符串匹配数据结构,核心在于利用 fail 指针在失配时将节点跳转到当前节点代表字符串的最长后缀子串. 首先对 模式串 建 ...

随机推荐

  1. pytorch神经网络层搭建方法

    神经网络层的搭建主要是两种方法,一种是使用类(继承torch.nn.Moudle),一种是使用torch.nn.Sequential来快速搭建. 1)首先我们先加载数据: import torchim ...

  2. PI薄膜相关的基本理论

    一.耐电晕的基本理论 在电场作用下,绝缘材料聚酰亚胺薄膜的部分区域发生放电短路的现象称为局部放电 根据局部放电发生部位的不同,可分为绝缘材料内部的局部放电.表面的局部放电.发生在导体边缘而周围气体被击 ...

  3. 统计学习方法 | 第3章 k邻近法 | 补充

    namedtuple 不必再通过索引值进行访问,你可以把它看做一个字典通过名字进行访问,只不过其中的值是不能改变的. sorted()适用于任何可迭代容器,list.sort()仅支持list(本身就 ...

  4. [转帖]2015年时的新闻:Debian GNU/Hurd 2015 发布

    Debian GNU/Hurd 2015 发布 oschina 发布于 2015年04月30日 https://www.oschina.net/news/62004/debian-gnu-hurd-2 ...

  5. SYN攻击源码

    一.linux下源代码实现/* syn flood by wqfhenanxc. * random soruce ip and random sourec port. * use #include & ...

  6. 树状数组+二维前缀和(A.The beautiful values of the palace)--The Preliminary Contest for ICPC Asia Nanjing 2019

    题意: 给你螺旋型的矩阵,告诉你那几个点有值,问你某一个矩阵区间的和是多少. 思路: 以后记住:二维前缀和sort+树状数组就行了!!!. #define IOS ios_base::sync_wit ...

  7. thinkPHP验证码报错: Call to undefined function captcha_src()

    问题出现的原因可能有: 1. captcha扩展缺失: 2. captcha扩展与当前thinkPHP版本不兼容. thinkPHP6.0以下版本只能使用 captcha2.0以下版本,不支持2.0版 ...

  8. Fiddler--手机端抓包

    1.打开fiddler,点击Tools--options 2.勾选 3.确保手机与电脑连接同一个WIFI 4.打开手机无线网络,选择连接的WiFi,然后在代理选择手动,输入ip和端口号,查看本机ip

  9. dubbo看这一篇就够了

    为什么要有分布式 近年来微服务.分布式等名词非常的火,那么我们又为什么要进行系统拆分?如何进行拆分呢?阿里的dubbo作为分布式框架的代表,无疑是推动了整个行业技术的进步.以前中小型公司都是一个war ...

  10. 07-django项目连接远程mysql数据库

    比如电脑a(ip地址为192.168.0.aaa)想要连接访问电脑b(ip地址为192.168.0.bbb)的数据库: 对电脑a(ip地址为192.168.0.aaa): 在项目settings.py ...