题意

题目链接

分析

考虑枚举每个点的答案,最后除以 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. vs2012

    https://www.microsoft.com/zh-CN/download/confirmation.aspx?id=36020

  2. Error generating final archive: Unable to get debug signature key

    在调试程序时,发生下面的错误: Error generating final archive: Unable to get debug signature key 解决办法: 删除下面的文件: C:\ ...

  3. 从《数据挖掘概念与技术》到《Web数据挖掘》

    从<数据挖掘概念与技术>到<Web数据挖掘> 认真读过<数据挖掘概念与技术>的第一章后,对数据挖掘有了更加深刻的了解.数据挖掘是知识发展过程的一个步骤.知识发展的过 ...

  4. sql语句语句中的正则查找

    举例: select tncl_id from tncl where tncl_id regexp'^0065'; 有一表,数据有10万多条,其中某列数据示例如下: 100000-200000-300 ...

  5. LinUX系统ThinkPHP5链接MsSQL数据库的pdo_dblib扩展

    LinUX(centOS6.8)系统ThinkPHP5链接MsSQL数据库的pdo_dblib扩展第一步 下载并安装freetds-current.tar.gz下载地址如下ftp://ftp.free ...

  6. Centos 7 手把手教你使用YUM方式安装并配置Nginx+php7-fpm+MySQL

    需要准备的内容 一台纯净系统的服务器 远程连接服务器的工具 (我这里使用Xshell) 安装nginx 链接上服务器后执行 yum install nginx  这里需要输入y 后回车,开始安装ngi ...

  7. 用word2016 写CSDN 博客

    目前大部分的博客作者在用Word写博客这件事情上都会遇到以下3个痛点: 1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.使用Word写 ...

  8. URAL1991 The battle near the swamp 2017-04-12 18:07 92人阅读 评论(0) 收藏

    The battle near the swamp Gungan: Jar Jar, usen da booma!  Jar Jar: What? Mesa no have a booma!  Gun ...

  9. android事件分发

    1). android对事件分发的顺序为:Activity--->PhoneWindow--->DecorView--->yourView; 2). android控件对事件处理的优 ...

  10. [转载]关于JAVA中子类和父类的构造方法

    原文链接:https://www.cnblogs.com/chenpi/p/5486096.html#_label0