[ZJOI2019]语言[树链的并、线段树合并]
题意
分析
考虑枚举每个点的答案,最后除以 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]语言[树链的并、线段树合并]的更多相关文章
- bzoj 4034 [HAOI2015] T2(树链剖分,线段树)
4034: [HAOI2015]T2 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1536 Solved: 508[Submit][Status] ...
- bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)
1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 10677 Solved: 4313[Submit ...
- poj 3237 Tree(树链剖分,线段树)
Tree Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 7268 Accepted: 1969 Description ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- bzoj 2243 [SDOI2011]染色(树链剖分,线段树)
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4637 Solved: 1726[Submit][Status ...
- HDU 4366 Successor(树链剖分+zkw线段树+扫描线)
[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=4366 [题目大意] 有一个公司,每个员工都有一个上司,所有的人呈树状关系,现在给出每个人的忠诚值和 ...
- 【BZOJ3531】旅行(树链剖分,线段树)
[BZOJ3531]旅行(树链剖分,线段树) 题面 Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教 ...
- 【BZOJ5507】[GXOI/GZOI2019]旧词(树链剖分,线段树)
[BZOJ5507][GXOI/GZOI2019]旧词(树链剖分,线段树) 题面 BZOJ 洛谷 题解 如果\(k=1\)就是链并裸题了... 其实\(k>1\)发现还是可以用类似链并的思想,这 ...
- [bzoj4196][Noi2015]软件包管理器_树链剖分_线段树
软件包管理器 bzoj-4196 Noi-2015 题目大意:Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件 ...
- 【洛谷5439】【XR-2】永恒(树链剖分,线段树)
[洛谷5439][XR-2]永恒(树链剖分,线段树) 题面 洛谷 题解 首先两个点的\(LCP\)就是\(Trie\)树上的\(LCA\)的深度. 考虑一对点的贡献,如果这两个点不具有祖先关系,那么这 ...
随机推荐
- Spring JMX之三:通知的处理及监听
通过查询MBean获得信息只是查看应用状态的一种方法.但当应用发生重要事件时,如果希望 能够及时告知我们,这通常不是最有效的方法. 例如,假设Spittr应用保存了已发布的Spittle数量,而我们希 ...
- radiobutton 选中的项不能去掉选择的问题
代码如下: RadioButton rbtn = new RadioButton(getApplicationContext()); rbtn.setText(String.valueOf(item. ...
- ie高版本浏览器不支持velocity的问题解决
<head><meta http-equiv="X-UA-Compatible" content="IE=5"></head> ...
- Oracle学习笔记(六)
八.函数 1.函数的作用 (1)方便数据的统计 (2)处理查询结果,让数据显示更清楚 2.函数分类(提供很多内置函数,也可自定义函数) (1)数值函数 平均值,四舍五入 a.四舍五入 表达式 roun ...
- select for update [nowait]
Syntax The NOWAIT and WAIT clauses let you tell the database how to proceed if the SELECT statement ...
- loadrunner - Run time Settings 的详细说明
本文主要讲解一下run-time settings(如图1所示)里各设置项的具体含义(注:标红色的选项卡是比较值得关注的,可重点看一下): 图1 1.General / Run Logic 选项卡 ...
- 关于SQLServer无法对数据库'XXX'执行删除,因为它正用于复制。错误:'3724' 的解决方案
关于这个错误,是因为在服务器上想把数据库复制到本地,使用了“发布.订阅”方案,结果后来没成功,删除本地数据库的时候出现了这个错误,说“无法对数据库'XXX'执行删除,因为它正用于复制”. 解决方案:只 ...
- Oracle EBS Color 色彩设置
Oracle EBS配色方案的截图 If the Java Look and Feel profile option is set to Oracle, the Java Color Scheme c ...
- [记]Centos下流量统计使用记录
因为最近要进行centos流量统计,需求是想针对tomcat进行针对性的上下行流量时段统计及汇总,找了很多资料及命令,要么是可以针对进程的但是没有汇总,要么是有汇总但是不针对进程. 所以只能混合几个命 ...
- 在SharePoint列表中使用动态筛选条件[今日][Today]
如果在SharePoint使用了日历控件或者其他列表中有时间字段,用户经常希望能够动态使用条件字段进行筛选,例如希望筛选出开始日期是今天的事件.未来三日的事件. SharePoint的列表筛选条件支持 ...