考虑把贡献摊到每个点上计算,每个点带来的贡献实际上是经过它的路径并大小,算完求和之后在除以 \(2\) 就得到了答案。

考虑怎么计算路径并大小。

考虑这样一个办法,将所有路径的起始点和终点按照 DFS 序排序,相邻两点(包括第一个会最后一个点)在树上的距离之和便是其路径并大小的两倍。原理的话便是路径并大小等价于包含所有路径起始点的最小联通生成树。

考虑树上点差分,然后用线段树储存 DFS 序为 \(x\) 的点是否在子树中,维护节点内最大和最小的存在的 DFS 序就可以在通过一次求 LCA 合并两个子节点的信息。

那么最后一步通过线段树合并将子树的信息合并到父亲即可。

时间复杂度 \(O(n \log^2 n)\) 空间复杂度 \(O(n \log n)\),也可以通过写压缩 01Trie 或者直接维护线段树叶子节点的方法做到线性空间,但没什么必要。

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e5 + 114;
int fa[maxn][19], lg[maxn];
int dfn[maxn], dfncnt, dep[maxn];
int Node[maxn];
int n, m;
vector<int> edge[maxn];
void dfs1(int u, int father) {
dep[u] = dep[father] + 1;
dfn[u] = ++dfncnt;
Node[dfncnt] = u;
fa[u][0] = father; for (int i = 1; i <= 17; i++)
fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int v : edge[u]) {
if (v == father)
continue; dfs1(v, u);
}
}
int LCA(int u, int v) {
if (dep[u] < dep[v])
swap(u, v); while (dep[u] > dep[v]) {
u = fa[u][lg[dep[u] - dep[v]]];
} if (u == v)
return u; for (int i = 17; i >= 0; i--) {
if (fa[u][i] != fa[v][i]) {
u = fa[u][i], v = fa[v][i];
}
} return fa[u][0];
}
int dist(int x, int y) {
return dep[x] + dep[y] - 2 * dep[LCA(x, y)];
}
#define ls(cur)(tr[cur].ls)
#define rs(cur)(tr[cur].rs)
int tot;
struct Segment_tree {
int ls, rs;
int mi, mx, sum, cnt;
} tr[maxn * 40];
int root[maxn];
void pushup(int cur) {
tr[cur].cnt = tr[ls(cur)].cnt + tr[rs(cur)].cnt; if (tr[ls(cur)].cnt == 0 && tr[rs(cur)].cnt == 0)
cur = 0;
else if (tr[ls(cur)].cnt == 0)
tr[cur].sum = tr[rs(cur)].sum, tr[cur].mi = tr[rs(cur)].mi, tr[cur].mx = tr[rs(cur)].mx;
else if (tr[rs(cur)].cnt == 0)
tr[cur].sum = tr[ls(cur)].sum, tr[cur].mi = tr[ls(cur)].mi, tr[cur].mx = tr[ls(cur)].mx;
else {
tr[cur].sum = tr[ls(cur)].sum + tr[rs(cur)].sum + dist(Node[tr[ls(cur)].mx], Node[tr[rs(cur)].mi]);
tr[cur].mi = tr[ls(cur)].mi;
tr[cur].mx = tr[rs(cur)].mx;
}
}
void update(int &cur, int lt, int rt, int pos, int v) {
if (pos < lt || pos > rt)
return ; if (cur == 0)
cur = ++tot; if (lt == rt && lt == pos) {
tr[cur].cnt += v;
tr[cur].mi = tr[cur].mx = lt;
tr[cur].sum = 0;
return ;
} int mid = (lt + rt) >> 1;
update(ls(cur), lt, mid, pos, v);
update(rs(cur), mid + 1, rt, pos, v);
pushup(cur);
}
int merge(int a, int b, int lt, int rt) {
if (a == 0 || b == 0)
return a + b; if (lt == rt) {
tr[a].cnt += tr[b].cnt;
tr[a].mi = tr[a].mx = lt;
tr[a].sum = 0;
return a;
} int mid = (lt + rt) >> 1;
tr[a].ls = merge(tr[a].ls, tr[b].ls, lt, mid);
tr[a].rs = merge(tr[a].rs, tr[b].rs, mid + 1, rt);
pushup(a);
return a;
}
vector<int> Ins[maxn], Del[maxn];
int answer;
void dfs2(int u, int father) {
for (int v : edge[u]) {
if (v == father)
continue; dfs2(v, u);
root[u] = merge(root[u], root[v], 1, n);
} for (int x : Ins[u])
update(root[u], 1, n, x, 1); for (int x : Del[u])
update(root[u], 1, n, x, -1); answer += (tr[root[u]].sum + dist(Node[tr[root[u]].mi], Node[tr[root[u]].mx])) / 2;
}
signed main() {
cin >> n >> m;
lg[1] = 0; for (int i = 2; i <= n; i++)
lg[i] = lg[i / 2] + 1; for (int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
edge[u].push_back(v);
edge[v].push_back(u);
} dep[0] = -1;
dfs1(1, 0); for (int i = 1; i <= m; i++) {
int u, v;
cin >> u >> v; if (u == v)
continue; Ins[u].push_back(dfn[u]);
Ins[u].push_back(dfn[v]);
Ins[v].push_back(dfn[v]);
Ins[v].push_back(dfn[u]);
Del[LCA(u, v)].push_back(dfn[u]);
Del[LCA(u, v)].push_back(dfn[v]);
Del[fa[LCA(u, v)][0]].push_back(dfn[u]);
Del[fa[LCA(u, v)][0]].push_back(dfn[v]);
} dfs2(1, 0);
cout << answer / 2;
}

P5327 题解的更多相关文章

  1. 题解 P5327 [ZJOI2019]语言

    P5327 [ZJOI2019]语言 解题思路 暴力 首先讲一下我垃圾的 40pts 的暴力(其他 dalao 都是 60pts 起步): 当然评测机快的话(比如 LOJ 的),可以卡过 3,4 个点 ...

  2. 【题解】Luogu P5327 [ZJOI2019]语言

    原题传送门 看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外 先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[l ...

  3. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  4. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  5. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  6. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  7. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  8. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  9. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  10. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

随机推荐

  1. blazor中的PageTitle输出keywords和description,自定义组件

    在blazor的PageTitle中不具备输出keywords和description的功能,而如果直接使用<mate>标签,输出中文时会变成乱码,所以我给大家推介下面的代码解君愁: 1 ...

  2. golang基础之结构体

    匿名结构体 在定义一些临时数据结构等场景下还可以使用匿名结构体. 在函数体内 package main import ( "fmt" ) func main() { //方法一 v ...

  3. 【漏洞复现】Apache RocketMQ 代码注入漏洞(CVE-2023-37582)

    产品介绍 Apache RocketMQ是美国阿帕奇(Apache)基金会的一款轻量级的数据处理平台和消息传递引擎. 漏洞概述 Apache RocketMQ 存在代码注入漏洞,该漏洞源于当 Name ...

  4. 国产Linux音视频聊天程序开发遇到的坑及解决:相互听不到对方声音?

    最近完成了一个银河麒麟上的视频聊天项目,在我们开发机上测试一切正常后,提交给甲方测试.结果发现在甲方的某些银河麒麟V10的电脑上,听不到声音. 这个问题,使用<Avalonia 实现跨平台的IM ...

  5. C# winform GDI+ 五子棋 (一):基本界面和胜负判断

    棋盘和棋子采用GDI+画上去的.棋盘18*18.棋子是用DrawElipse画的,白棋和黑棋分两个List集合存储,方便判断五子连线的情况. 主要说一下,五子连线的思路,把集合按行和按列以及按正斜和反 ...

  6. 首次调用u8api遇到的问题总结

    1.检索 COM 类工厂中 CLSID 为 {72A6FADA-FE26-46BD-A921-BFD1179C1E1E} 的组件时失败,原因是出现以下错误: 80040154.   解决办法是,把编译 ...

  7. pwn杂项之linux命令执行

    通常pwn题目,时常会考到对Linux命令的一些使用,比如当cat被禁用的时候,可以使用tac,或者别的命令代替 下面是buu上的应该题目,考察的就是对liunx命令的理解,以及对程序的分析. 题目地 ...

  8. WPF开发快速入门【3】WPF的基本特性(附加属性)

    概述 本文描述WPF的附加属性.对于使用MVVM框架的项目,附加属性是非常重要的一个特性. 在MVVM框架下,ViewModel的代码通过控件的依赖属性来控制控件的,例如: //ViewModel p ...

  9. 23ai中的True Cache到底能做啥?

    最近,Oracle的产品管理总监在Oracle数据库内幕中介绍了True Cache. 原文链接如下: https://blogs.oracle.com/database/post/introduci ...

  10. 鸿蒙极速入门(三)-TypeScript语言简介

    ArkTS是HarmonyOS优选的主力应用开发语言.ArkTS围绕应用开发在TypeScript(简称TS)生态基础上做了进一步扩展,继承了TS的所有特性,是TS的超集.因此,在学习ArkTS语言之 ...