题意

题目链接

分析

考虑枚举每个点的答案,最后除以 2 即可。

可以与 \(u\) 构成合法点对的点集为所有经过了 \(u\) 的链的并。因为这些链两两有交,所以它们的并集构成了一棵树。

考虑维护经过每个点的链并集的大小。一条链是否出现可以树上差分,并集的具体大小就以 \(dfs\) 序为下标建线段树,然后线段树合并即可。

复杂度 \(O(n\log n)\) 。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define go(u) for(int i = head[u], v = e[i].to; i; i = e[i].lst, v = e[i].to)
#define rep(i, a, b) for(int i = a; i <= b; ++i)
#define pb push_back
inline int gi() {
int x = 0,f = 1;
char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) { x = (x << 3) + (x << 1) + ch - 48; ch = getchar();}
return x * f;
}
template <typename T> inline bool Max(T &a, T b){return a < b ? a = b, 1 : 0;}
template <typename T> inline bool Min(T &a, T b){return a > b ? a = b, 1 : 0;}
const int N = 1e5 + 7;
LL ans;
int n, m, edc, elc, ndc, tim;
int head[N], fa[N], in[N], out[N], fie[N], Log[N << 1], dep[N];
typedef pair<int, int> pii;
pii mi[N << 1][20];
struct edge {
int lst, to;
edge(){}edge(int lst, int to):lst(lst), to(to){}
}e[N << 1];
void Add(int a, int b) {
e[++edc] = edge(head[a], b), head[a] = edc;
e[++edc] = edge(head[b], a), head[b] = edc;
}
void dfs1(int u) {
in[u] = ++tim;
mi[++elc][0] = make_pair(in[u], u);
fie[u] = elc;
go(u)if(v ^ fa[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
mi[++elc][0] = make_pair(in[u], u);
}
out[u] = tim;
}
int Lca(int l, int r) {
l = fie[l], r = fie[r];
if(l > r) swap(l, r);
int k = Log[r - l + 1];
return min(mi[l][k], mi[r - (1 << k) + 1][k]).second;
}
int rt[N];
vector<int>G[N];
struct node {int l, r, A, B, cnt, s;}t[N * 150];
#define Ls t[o].l
#define Rs t[o].r
void pushup(int o) {
t[o].A = t[Ls].A ? t[Ls].A : t[Rs].A;
t[o].B = t[Rs].B ? t[Rs].B : t[Ls].B;
t[o].s = t[Ls].s + t[Rs].s;
if(t[Ls].B && t[Rs].A) t[o].s -= dep[Lca(t[Ls].B, t[Rs].A)];
}
void modify(int p, int l, int r, int &o, int v) {
if(!o) o = ++ndc;
if(l == r) {
t[o].cnt += v;
if(t[o].cnt) t[o].A = t[o].B = p, t[o].s = dep[p];
else t[o].A = t[o].B = t[o].s = 0;
return;
}int mid = l + r >> 1;
if(in[p] <= mid) modify(p, l, mid, Ls, v);
else modify(p, mid + 1, r, Rs, v);
pushup(o);
}
int merge(int l, int r, int x, int y) {
if(!x || !y) return x + y;
if(l == r) {
t[x].cnt += t[y].cnt;
if(t[x].cnt) t[x].A = t[x].B = max(t[x].A, t[y].A), t[x].s = dep[t[x].A];
else t[x].A = t[x].B = t[x].s = 0;
return x;
}int mid = l + r >> 1;
t[x].l = merge(l, mid, t[x].l, t[y].l);
t[x].r = merge(mid + 1, r, t[x].r, t[y].r);
return pushup(x), x;
}
void dfs2(int u) {
go(u)if(v ^ fa[u]) {
dfs2(v);
rt[u] = merge(1, n, rt[u], rt[v]);
}
for(auto v:G[u]) modify(v, 1, n, rt[u], -2);
if(t[rt[u]].A && t[rt[u]].B)
ans += t[rt[u]].s - dep[fa[Lca(t[rt[u]].A, t[rt[u]].B)]] - 1;
}
int main() {
n = gi(), m = gi();
rep(i, 1, n - 1)
Add(gi(), gi());
dep[1] = 1, dfs1(1);
for(int k = 1; 1 << k <= elc; ++k)
for(int i = 1; i + (1 << k) - 1 <= elc; ++i)
mi[i][k] = min(mi[i][k - 1], mi[i + (1 << k - 1)][k - 1]);
for(int i = 2; i <= elc; ++i)
Log[i] = Log[i >> 1] + 1;
rep(i, 1, m) {
int x = gi(), y = gi(), lca = Lca(x, y);
modify(x, 1, n, rt[x], 1);
modify(y, 1, n, rt[x], 1);
modify(x, 1, n, rt[y], 1);
modify(y, 1, n, rt[y], 1);
if(fa[lca]) G[fa[lca]].pb(x), G[fa[lca]].pb(y);
}
dfs2(1);
printf("%d\n", ndc);
printf("%lld\n", ans / 2);
return 0;
}

[ZJOI2019]语言[树链的并、线段树合并]的更多相关文章

  1. bzoj 4034 [HAOI2015] T2(树链剖分,线段树)

    4034: [HAOI2015]T2 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1536  Solved: 508[Submit][Status] ...

  2. bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

    1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit ...

  3. poj 3237 Tree(树链剖分,线段树)

    Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description ...

  4. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  5. bzoj 2243 [SDOI2011]染色(树链剖分,线段树)

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4637  Solved: 1726[Submit][Status ...

  6. HDU 4366 Successor(树链剖分+zkw线段树+扫描线)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...

  7. 【BZOJ3531】旅行(树链剖分,线段树)

    [BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...

  8. 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)

    [BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...

  9. [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树

    软件包管理器 bzoj-4196 Noi-2015 题目大意:Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件 ...

  10. 【洛谷5439】【XR-2】永恒(树链剖分,线段树)

    [洛谷5439][XR-2]永恒(树链剖分,线段树) 题面 洛谷 题解 首先两个点的\(LCP\)就是\(Trie\)树上的\(LCA\)的深度. 考虑一对点的贡献,如果这两个点不具有祖先关系,那么这 ...

随机推荐

  1. Facebook对MySQL全表扫描性能的改进

    原文博客如下: http://yoshinorimatsunobu.blogspot.com/2013/10/making-full-table-scan-10x-faster-in.html 如下是 ...

  2. 让Ubuntu使用阿里云国内源,解决下载速度慢问题。

    阿里云镜像官方地址 http://mirrors.aliyun.com/ 找到最新源地址列表: http://www.linuxdiyf.com/linux/23163.html 软件包管理中心(推荐 ...

  3. centos搭建本地yum源,

    比如将文件夹:/opt/mir/这个文件夹做成本地源: 1.在/etc/yum.repos.d/目录下新建一个.repo文件,比如mir-base.repo,在里面加入如下: [local]name= ...

  4. tp5主从数据库设置读写分离

    // 数据库类型 'type' => 'mysql', // 服务器地址 'hostname' => '192.168.0.5,192.168.0.6', // 数据库名 'databas ...

  5. Debug_with_docker_in_pycharm

    Debug with docker in pycharm Why As I really really appreciate it that we can have a isolated develo ...

  6. Spring 框架简介

    Spring 是一个开源框架,是为了解决企业应用程序开发复杂性而创建的.框架的主要优势之一就是其分层架构,分层架构允许您选择使用哪一个组件,同时为 J2EE 应用程序开发提供集成的框架. 在这篇由三部 ...

  7. ORACLE ERP 的前世今生

    一个伟大的公司必有一个伟大的产品.如果说数据库是ORACLE在上世纪最后二十年赖以起家并奠定江湖地位的旗舰产品,那么,企业应用产品(或曰ERP)则毫无疑问是ORACLE在本世纪初的这近十年,征战疆场. ...

  8. 封装MongoDB的 asp.net 链接类

    using System;using System.Collections.Generic;using System.Linq;using MongoDB; /// <summary>// ...

  9. session概要

    一.Session简单介绍 在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况 下).因此,在需要保存用户数据时,服 ...

  10. mysql导入数据load data infile用法(转)

    们常常导入数据!mysql有一个高效导入方法,那就是load data infile 下面来看案例说明 基本语法: load data  [low_priority] [local] infile ' ...