P4211 [LNOI2014]LCA

有一棵根节点为111树,有mmm次询问,每次给定l,r,zl, r, zl,r,z,输出∑i=lrdep[lca(i,z)]\sum\limits_{i = l} ^{r} dep[lca(i, z)]i=l∑r​dep[lca(i,z)]。

乍一看这题好像无从下手,仔细想想lca(i,z)lca(i, z)lca(i,z)有何性质,不难发现lca(i,z)lca(i, z)lca(i,z)一定是在1−>z1->z1−>z的路径上的,

那么我们的答案求解就可以转换为每次对i−>1i->1i−>1路径上的点加一,求z−>1z->1z−>1上路径上的点的和即为我们要求的答案。

考虑如何优化这一过程:

离线求解:

将每个询问(l,r,z)(l, r, z)(l,r,z)拆分成(1,l−1,z),(1,r,z)(1, l - 1, z), (1, r, z)(1,l−1,z),(1,r,z),那么答案就为(1,r,z)−(1,l−1,z)(1, r, z) - (1, l - 1, z)(1,r,z)−(1,l−1,z)了,

我们将所有拆分后询问按照rrr排个序,从小到大每次插入点iii,如果当前插入的点iii等于每个询问的rrr则统计一次答案,

两点之间点权的信息更新可以考虑树剖,注意答案的加减,最后输出答案即可,整体复杂度O(nlog⁡nlog⁡n)O(n \log n \log n)O(nlognlogn)。

#include <bits/stdc++.h>
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1using namespace std;const int N = 1e5 + 10, mod = 201314;int head[N], to[N], nex[N], cnt = 1;int fa[N], dep[N], sz[N], son[N], rk[N], id[N], top[N], tot;int sum[N << 2], lazy[N << 2], ans[N], n, m;struct Res {int u, v, id;bool operator < (const Res &t) {return u < t.u;}
}a[N];void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void dfs1(int rt, int f) {fa[rt] = f, dep[rt] = dep[f] + 1, sz[rt] = 1;for (int i = head[rt]; i; i = nex[i]) {if (to[i] == f) {continue;}dfs1(to[i], rt);sz[rt] += sz[to[i]];if (!son[rt] || sz[son[rt]] < sz[to[i]]) {son[rt] = to[i];}}
}void dfs2(int rt, int tp) {top[rt] = tp, rk[++tot] = rt, id[rt] = tot;if (!son[rt]) {return ;}dfs2(son[rt], tp);for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa[rt] || to[i] == son[rt]) {continue;}dfs2(to[i], to[i]);}
}void push_up(int rt) {sum[rt] = (sum[ls] + sum[rs]) % mod;
}void push_down(int rt, int l, int r) {if (lazy[rt]) {lazy[ls] = (lazy[ls] + lazy[rt]) % mod, lazy[rs] = (lazy[rs] + lazy[rt]) % mod;sum[ls] = (sum[ls] + 1ll * (mid - l + 1) * lazy[rt]) % mod;sum[rs] = (sum[rs] + 1ll * (r - mid) * lazy[rt]) % mod;lazy[rt] = 0;}
}void update(int rt, int l, int r, int L, int R, int v) {if (l >= L && r <= R) {lazy[rt] = (lazy[rt] + 1) % mod;sum[rt] = (sum[rt] + r - l + 1) % mod;return ;}push_down(rt, l, r);if (L <= mid) {update(lson, L, R, v);}if (R > mid) {update(rson, L, R, v);}push_up(rt);
}int query(int rt, int l, int r, int L, int R) {if (l >= L && r <= R) {return sum[rt];}push_down(rt, l, r);int ans = 0;if (L <= mid) {ans = query(lson, L, R);}if (R > mid) {ans = (ans + query(rson, L, R)) % mod;}return ans;
}void update(int rt) {while (rt) {update(1, 1, n, id[top[rt]], id[rt], 1);rt = fa[top[rt]];}
}int query(int rt) {int ans = 0;while (rt) {ans = (ans + query(1, 1, n, id[top[rt]], id[rt])) % mod;rt = fa[top[rt]];}return ans;
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%d %d", &n, &m);for (int i = 2, fa; i <= n; i++) {scanf("%d", &fa);add(fa + 1, i);}dfs1(1, 0);dfs2(1, 1);for (int i = 1, l, r, u; i <= m; i++) {scanf("%d %d %d", &l, &r, &u);l++, r++, u++;a[i * 2 - 1] = {l - 1, u, i * 2 - 1};a[i * 2] = {r, u, i * 2};}sort(a + 1, a + 1 + 2 * m);int cur = 1;while (cur <= 2 * m && a[cur].u == 0) {cur++;    }for (int i = 1; i <= n; i++) {update(i);while (cur <= 2 * m && a[cur].u == i) {int res = query(a[cur].v);if (a[cur].id & 1) {ans[a[cur].id + 1 >> 1] = (ans[a[cur].id + 1 >> 1] + mod - res) % mod;}else {ans[a[cur].id >> 1] = (ans[a[cur].id >> 1] + res) % mod;}cur++;}}for (int i = 1; i <= m; i++) {printf("%d\n", ans[i]);}return 0;
}

在线求解:

考虑主席树,第iii棵主席树为前i−1i - 1i−1棵主席树的信息 + 节点编号为iii的点到根节点权值都+1+1+1的信息。

不难想到,最后我们的答案就是在[l,r][l, r][l,r]区间的主席树上查询在1−>z1->z1−>z之间的点的权值和。

主席树上打lazylazylazy,空间按道理应该是O(nlog⁡nlog⁡n)O(n \log n \log n)O(nlognlogn)级别的,支持在线求解时间复杂度也是O(nlog⁡nlog⁡n)O(n \log n \log n)O(nlognlogn)级别的。

#include <bits/stdc++.h>using namespace std;const int N = 5e4 + 10, mod = 201314;int head[N], to[N], nex[N], cnt = 1;int fa[N], son[N], sz[N], top[N], dep[N], rk[N], id[N], tot;int root[N], ls[N * 200], rs[N * 200], sum[N * 200], lazy[N * 200], n, m, num;void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void dfs1(int rt, int f) {fa[rt] = f, dep[rt] = dep[f] + 1, sz[rt] = 1;for (int i = head[rt]; i; i = nex[i]) {if (to[i] == f) {continue;}dfs1(to[i], rt);sz[rt] += sz[to[i]];if (!son[rt] || sz[son[rt]] < sz[to[i]]) {son[rt] = to[i];}}
}void dfs2(int rt, int tp) {top[rt] = tp, rk[++tot] = rt, id[rt] = tot;if (!son[rt]) {return ;}dfs2(son[rt], tp);for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa[rt] || to[i] == son[rt]) {continue;}dfs2(to[i], to[i]);}
}void update(int &rt, int pre, int l, int r, int L, int R, int v) {rt = ++num;ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = sum[pre], lazy[rt] = lazy[pre];sum[rt] = (sum[rt] + 1ll * (min(r, R) - max(l, L) + 1) * v) % mod;if (l >= L && r <= R) {lazy[rt] = (lazy[rt] + v) % mod;return ;}int mid = l + r >> 1;if (L <= mid) {update(ls[rt], ls[pre], l, mid, L, R, v);}if (R > mid) {update(rs[rt], rs[pre], mid + 1, r, L, R, v);}
}int query(int rt1, int rt2, int l, int r, int L, int R) {if (l >= L && r <= R) {return (sum[rt2] - sum[rt1] + mod) % mod;}int mid = l + r >> 1, ans = (1ll * (min(r, R) - max(l, L) + 1) * (lazy[rt2] - lazy[rt1]) % mod + mod) % mod;if (L <= mid) {ans = (ans + query(ls[rt1], ls[rt2], l, mid, L, R)) % mod;}if (R > mid) {ans = (ans + query(rs[rt1], rs[rt2], mid + 1, r, L, R)) % mod;}return ans;
}int query(int l, int r, int rt) {int ans = 0;while (rt) {ans = (ans + query(root[l], root[r], 1, n, id[top[rt]], id[rt])) % mod;rt = fa[top[rt]];}return ans;
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d %d", &n, &m);for (int i = 2, fa; i <= n; i++) {scanf("%d", &fa);add(fa + 1, i);}dfs1(1, 0);dfs2(1, 1);for (int i = 1; i <= n; i++) {int rt = i;root[i] = root[i - 1];while (rt) {update(root[i], root[i], 1, n, id[top[rt]], id[rt], 1);rt = fa[top[rt]];}}for (int i = 1, l, r, rt; i <= m; i++) {scanf("%d %d %d", &l, &r, &rt);l++, r++, rt++;printf("%d\n", query(l - 1, r, rt));}return 0;
}

P4211 [LNOI2014]LCA(离线 + 在线 做法)相关推荐

  1. 【做题记录】P4211 [LNOI2014]LCA

    P4211 [LNOI2014]LCA 题意 给出一个 \(n\) 个节点的有根树(编号为 \(0\) 到 \(n-1\),根节点为 \(0\)). 一个点的深度定义为这个节点到根的距离 \(+1\) ...

  2. [BZOJ3626] [LNOI2014] LCA 离线 树链剖分

    题面 考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\). 显然这些LCA一定在\(z\)到根的路径上.下面的问题就是怎么统计. 考虑不是那么暴力的暴 ...

  3. bzoj 3626: [LNOI2014]LCA(离线差分+树链剖分)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 2885  Solved: 1133 [Submit][Sta ...

  4. #HYSBZ3626[LNOI2014]#LCA(经典模型:树剖+线段树维护和)

    3626: [LNOI2014]LCA Time Limit: 10 Sec   Memory Limit: 128 MB Description 给出一个n个节点的有根树(编号为0到n-1,根节点为 ...

  5. BZOJ 3626: [LNOI2014]LCA

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 2074  Solved: 828 [Submit][Stat ...

  6. 【BZOJ 3626】 [LNOI2014]LCA

    3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MB Submit: 735 Solved: 250 [Submit][Status] ...

  7. Tableau使用教程:如何Tableau中添加离线/在线地图

    Tableau使用教程:如何Tableau中添加离线/在线地图 发布时间:2019-04-03 版权: 相关软件:BIGEMAP GIS Office软件 BIGEMAP可以提供Tableau多样化的 ...

  8. IOS音视频(四十六)离线在线语音识别方案

    IOS音视频(四十六)离线在线语音识别方案 IOS音视频(四十六)离线在线语音识别方案 方案一:Siri语音识别 Siri语音识别简介 Siri语音识别功能类介绍 Siri语音识别功能集成 方案二:百 ...

  9. 【线段树合并】解题报告:luogu P4556雨天的尾巴 (树上对点差分 + 动态开点 + 线段树合并)线段树合并模板离线/在线详解

    题目链接:雨天的尾巴 本题本身是一个非常简单的一道树上差分的模板题,但是由于变态的数据范围,我们直接用数组是存不下的(本来使用一颗普通的线段树直接维护最大值即可.但是本题的空间只有128MB,直接按照 ...

最新文章

  1. python下载文件并改名_第46p,8行代码,用Python批量重命名文件
  2. DIY人脸跟踪电风扇送女朋友(1)
  3. GET XXX net::ERR_CONNECTION_REFUSED
  4. y空间兑换代码_如何让Python代码加速运行?
  5. Python数据结构-列表
  6. 暴力解决mui框架跳转问题
  7. Homestead GuestAdditions seems to be installed (6.0.6) correctly, but not running
  8. 端口扫描:zenmap工具的使用
  9. 又一个同学被快手挂掉了
  10. Scaner和顺序语句
  11. linux 命令 置顶,[置顶] Linux命令惯用法
  12. P1719 最大加权矩形
  13. whl is not a supported wheel on this platform.解决办法
  14. Python计算Arduino声音方向范围和绘制声音位置二维概率分布热图
  15. python 菜品识别_菜品识别-python
  16. 指纹识别-(2)指纹图像的获取
  17. project子项目之间任务关联_任务日历关联(Project)
  18. 炫龙笔记本安装Ubantu系统
  19. Java开发工程师个人简历模板,简洁,给人正规,严谨的形象
  20. Linux的Scp命令简单描述

热门文章

  1. 计算机转财经专业考试考什么,高三对口升学第三次模拟考试财经基础课计算机专业课...
  2. 外圆内方与外方内圆的奇妙变换!
  3. 柠檬汁制成的电池可以开动超100千克的车子吗?
  4. 他从小把数学书当小说看,凭借一本书将全世界狠狠甩在身后,被誉为中国的牛顿...
  5. 听说这是和女朋友住一起后的现象之一
  6. 明天放假,我放价!一个国庆假期教你学会数学建模
  7. python34怎么安装_简明Python3教程 4.安装
  8. python生成器yield原理_Python generator生成器和yield表达式详解
  9. jwt如何防止token被窃取_在吗?认识一下JWT(JSON Web Token)?
  10. html 存储登录状态,Vue中保存用户登录状态实例代码