《高等理论计算机科学》,【hihocoder1167】高等理论计算机科学 (重链剖分 +树状数组)...

Descroption

原题链接给你一棵\(~n~\)个点的树和\(~m~\)条链,求两两相交的链有多少对,两条链相交当且仅当有至少一个公共点。\(~1 \leq n, m \leq 10 ^ 5~\).

Solution

一个很直观的想法是把每一条链路径上的权值\(+1\),然后计算每一条链内多出来的权值为多少,显然这样是错的,因为两条链的交集可能不止有一个点,那么可以把每一条链路径上的点权\(+1\),边权\(-1\),再算多出来多少就好了。然而我不会这个啊。

考虑一个性质:

两条链相交当且仅当一条链的\(LCA\)在另一条链上

至于怎么证明,可以画图推推反例发现找不到,为了方便,设两条链为\(C1,C2\),若\(~LCA_{C1}~\)不在\(~C2~\)内,可以有两种情况:\(~①~\)\(C1~\)和\(C2~\)没有交集.\(~②~\)\(LCA_{C2}~\)在\(~C1~\)上. 这基于树上结点的父亲的唯一性。于是就把每一条链的\(~LCA~\)的权值\(+1\),最后统计每一条链内权值和就好了,注意减去重复的情况。

Code

#include

#define For(i, j, k) for (int i = j; i <= k; ++i)

#define Travel(i, u) for (int i = beg[u], v = to[i]; i; v = to[i = nex[i]])

using namespace std;

inline int read() {

int x = 0, p = 1; char c = getchar();

for (; !isdigit(c); c = getchar()) if(c == '-') p = -1;

for (; isdigit(c); c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);

return x * p;

}

inline void File() {

freopen("P1167.in", "r", stdin);

freopen("P1167.out", "w", stdout);

}

typedef long long ll;

const int N = 1e5 + 10;

int e = 1, beg[N], nex[N << 1], to[N << 1], u, v, tmp[N];

int dep[N], dfn[N], top[N], fa[N], son[N], n, m, siz[N];

struct BIT {

int c[N];

inline void update(int x, int v) { for (; x <= n; x += x & -x) c[x] += v; }

inline int query(int x) { int res = 0; for (; x; x -= x & -x) res += c[x]; return res; }

inline int query(int l, int r) { return query(r) - query(l - 1);}

} T;

inline void add(int x, int y) {

to[++ e] = y, nex[e] = beg[x], beg[x] = e;

to[++ e] = x, nex[e] = beg[y], beg[y] = e;

}

inline void dfs1(int u, int f = 0) {

dep[u] = dep[fa[u] = f] + 1, siz[u] = 1;

Travel(i, u) if (v ^ f) {

dfs1(v, u), siz[u] += siz[v];

if (siz[v] > siz[son[u]]) son[u] = v;

}

}

int clk = 0;

inline void dfs2(int u) {

dfn[u] = ++ clk, top[u] = son[fa[u]] == u ? top[fa[u]] : u;

if (son[u]) dfs2(son[u]);

Travel(i, u) if (v ^ fa[u] && v ^ son[u]) dfs2(v);

}

inline int lca(int x, int y, int ty) {

int res = 0;

while (top[x] != top[y]) {

if (dep[top[x]] < dep[top[y]]) swap(x, y);

res += T.query(dfn[top[x]], dfn[x]), x = fa[top[x]];

}

if (dep[x] < dep[y]) swap(x, y);

return ty ? res + T.query(dfn[y], dfn[x]) : y;

}

struct Chain { int x, y, lca; } P[N];

int main() {

File();

n = read(), m = read();

For(i, 2, n) u = read(), v = read(), add(u, v);

dfs1(1), dfs2(1);

For(i, 1, m) {

P[i].x = read(), P[i].y = read();

++ tmp[P[i].lca = lca(P[i].x, P[i].y, 0)];

T.update(dfn[P[i].lca], 1);

}

ll ans = 0;

For(i, 1, m) ans += lca(P[i].x, P[i].y, 1) - 1;

For(i, 1, n) ans -= 1ll * tmp[i] * (tmp[i] - 1) >> 1ll;

cout << ans << endl;

return 0;

}

Aragorn&&num;39&semi;s Story 树链剖分&plus;线段树 &amp&semi;&amp&semi; 树链剖分&plus;树状数组

Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...

4&period;12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量

LINK:duoxiao OJ LCA on Tree 题目: 一道树链剖分+树状数组的神题. (直接nQ的暴力有50. 其实对于树随机的时候不难想到一个算法 对于x的修改 暴力修改到根. 对于儿子的 ...

hdu 3966 Aragorn&&num;39&semi;s Story(树链剖分&plus;树状数组&sol;线段树)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...

HDU 3966 &sol;&sol;&sol; 树链剖分&plus;树状数组

题意: http://acm.hdu.edu.cn/showproblem.php?pid=3966 给一棵树,并给定各个点权的值,然后有3种操作: I x y z : 把x到y的路径上的所有点权值加 ...

HDU 3966 Aragorn&&num;39&semi;s Story 树链剖分&plus;树状数组 或 树链剖分&plus;线段树

HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...

bzoj1146整体二分&plus;树链剖分&plus;树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 #include #include

HDU 5044 (树链剖分&plus;树状数组&plus;点&sol;边改查)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...

BZOJ 2758 Blinker的噩梦&lpar;扫描线&plus;熟练剖分&plus;树状数组&rpar;

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2758 题意:平面上有n个多边形(凸包和圆).任意两个多边形AB只有两种关系:(1) ...

hdu 3966 Aragorn&amp&semi;&num;39&semi;s Story&lpar;树链剖分&plus;树状数组&rpar;

pid=3966" target="_blank" style="">题目链接:hdu 3966 Aragorn's Story 题目大意:给定 ...

随机推荐

ios 弹出不同的键盘

iOS 提供了10种键盘类型,在开发中,我们可以根据不同的需求,选择不同的键盘样式,例如,当我们只需要输入手机号码时,可以选择纯数字类型的键盘(NumbersAndPunctuation),当我们需要 ...

poj1142&period;Smith Number(数学推导)

Smith Number Time Limit: 1 Sec  Memory Limit: 64 MB Submit: 825  Solved: 366 Description While skimm ...

mac 下用 brew 安装mongodb

转自:mac 下用 brew 安装mongodb 经过这位仁兄的文章指导,终于连上了mongodb. 启动mongo数据库,就是打开一个终端sudo mongod,然后打开另一个终端sudo mong ...

gcd 最大公约数 模版!

1: #define ll long long ll gcd(ll a,ll b) { ) { return b; }else { return gcd(b % a,a); } } 2: int64 ...

C&num;ShowCursor光标的显示与隐藏

使用using System.Runtime.InteropServices; [DllImport("user32.dll" , EntryPoint = "Sho ...

css实现响应式全屏背景

利用css中 background-size:cover  填充整个viewport 注意: 一张背景图像素5000px*5000px在pc端 缩放都基本满足要求 不会出现模糊失真: 但是在移动端使用 ...

HTML5简单入门系列(八)

前言 本篇介绍HTML5中相对复杂的一些APIs,其中的数学知识比较多.虽然如此,但是其实API使用起来还是比较方便的. 这里说明一下,只写出API相关的JS代码,因为他们都是基于一个canvas标签 ...

angular初始用——简易购物车

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值