题目大意:给定一棵 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. 例子 使用sqlite3 数据库建立数据方式

    #!/usr/bin/env python#coding:utf-8import sqlite3#建立一个数据库cx = sqlite3.connect("E:/test.db") ...

  2. HNU_团队项目_出现的Error总结_1

    今天开始记录开发中的Error,实时更新,以10条为一个博客,会给出相应的错误截图和解决方法.数据库框架Mybatis的配置和使用,详见之后发布的相关博客. 之后会对每一个错误进行分析,单独成一篇随笔 ...

  3. SQL常见面试题(学生表_课程表_总表)

    问题描述: 为管理岗位业务培训信息,建立3个表: S (S#,SN,SD,SA) S#,SN,SD,SA 分别代表学号.学员姓名.所属单位.学员年龄 C (C#,CN ) C#,CN 分别代表课程编号 ...

  4. 【HANA系列】SAP HANA SQL计算某日期是当年的第几天

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[HANA系列]SAP HANA SQL计算某日 ...

  5. SQL优化手段

    一.建立索引 要尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引(order by desc会非常影响效率). 二.避免在建立索引的字段进行计算操作. 三.使用预编 ...

  6. 【Python开发】Python PIL ImageDraw 和ImageFont模块学习

    ImageDraw 新建一个空白图片为本文作示例,新建空白文件的方法 见Image模块,Image.new: mport Image   blank = Image.new("RGB&quo ...

  7. 【DSP开发】TI第二代KeyStone SoC诠释德仪的“云”态度

    11月14日,期盼已久的德州仪器基于ARM Cortex-A15的产品终于新鲜出炉.伴随着TIKeyStone II多核 SoC系列产品的发布,结合了ARM Cortex-A15 处理器.C66x D ...

  8. mysql——插入、更新、删除数据(概念)

    一.插入数据 1.为表的所有字段插入数据 -------------------------------------------------------------------------- (1)i ...

  9. VBNET 文件信息和目录管理(判断,创建,删除,移动,复制)

    1.判断文件/目录是否存在 Try ' 先判断文件是否存在. If Not File.Exists(TextBox4.Text) Then File.CreateText(TextBox4.Text) ...

  10. Oracle-DDL 2- 视图&索引

    DDL-数据定义语句: 二.视图 --视图(view),本身不保存数据,保存的是一个查询语句--对视图的操作等同于对查询语句中源数据的操作--视图占用存储空间较小,可以快速的对特定数据进行访问和操作- ...