D. Misha, Grisha and Underground 树链剖分
D. Misha, Grisha and Underground
这个题目算一个树链剖分的裸题,但是这个时间复杂度注意优化。
这个题目可以选择树剖+线段树,时间复杂度有点高,比较这个本身就有n*logn*logn
但是就是lca+一点点思维就完全不卡时间。
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- #include <iostream>
- #include <algorithm>
- #include <cstdlib>
- #include <vector>
- #include <stack>
- #include <map>
- #include <string>
- #define inf 0x3f3f3f3f
- #define inf64 0x3f3f3f3f3f3f3f3f
- using namespace std;
- const int maxn = 2e5 + 10;
- int f[maxn];//f 保存u的父亲节点
- int dep[maxn];//dep保存节点u 的深度
- int siz[maxn];//siz保存以u为根的子节点的个数
- int son[maxn];//son 保存u的重儿子
- int rk[maxn];//rk当前dfs序在树中所对应的节点
- int top[maxn];// top保存当前结点所在链的顶端结点
- int id[maxn];//dfs的执行顺序
- int a[maxn];
- int n;
- int sum[maxn * 4], lazy[maxn * 4];
- //------------------线段树部分---------------//
- void push_up(int id) {
- sum[id] = (sum[id << 1] + sum[id << 1 | 1]);
- }
- void build(int id, int l, int r) {
- lazy[id] = -1;
- sum[id] = 0;
- if (l == r) return;
- int mid = (l + r) >> 1;
- build(id << 1, l, mid);
- build(id << 1 | 1, mid + 1, r);
- push_up(id);
- }
- void push_down(int id, int len1, int len2) {
- if (lazy[id] == -1) return;
- lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
- sum[id << 1] = len1 * lazy[id];
- sum[id << 1 | 1] = len2 * lazy[id];
- lazy[id] = -1;
- }
- void update(int id, int l, int r, int x, int y, int val) {
- // printf("id=%d l=%d r=%d x=%d y=%d val=%d\n", id, l, r, x, y, val);
- if (x <= l && y >= r) {
- sum[id] = (r - l + 1)*val;
- lazy[id] = val;
- return;
- }
- int mid = (l + r) >> 1;
- push_down(id, mid - l + 1, r - mid);
- if (x <= mid) update(id << 1, l, mid, x, y, val);
- if (y > mid) update(id << 1 | 1, mid + 1, r, x, y, val);
- push_up(id);
- }
- int query(int id, int l, int r, int x, int y) {
- if (x <= l && y >= r) return sum[id];
- int mid = (l + r) >> 1, ans = 0;
- push_down(id, mid - l + 1, r - mid);
- if (x <= mid) ans = (ans + query(id << 1, l, mid, x, y));
- if (y > mid) ans = (ans + query(id << 1 | 1, mid + 1, r, x, y));
- return ans;
- }
- //------------------------树链剖分-------------------//
- // int f[maxn];//f 保存u的父亲节点
- // int dep[maxn];//dep保存节点u 的深度
- // int siz[maxn];//siz保存以u为根的子节点的个数
- // int son[maxn];//son 保存u的重儿子
- // int rk[maxn];//rk当前dfs序在树中所对应的节点
- // int top[maxn];// top保存当前结点所在链的顶端结点
- // int id[maxn];//dfs的执行顺序
- struct node {
- int v, nxt;
- node(int v = 0, int nxt = 0) :v(v), nxt(nxt) {}
- }ex[maxn];
- int head[maxn], cnt = 0, tot;
- void init() {
- cnt = 0, tot = 0;
- memset(son, 0, sizeof(son));
- memset(head, -1, sizeof(head));
- }
- void add(int u, int v) {
- ex[cnt] = node(v, head[u]);
- head[u] = cnt++;
- ex[cnt] = node(u, head[v]);
- head[v] = cnt++;
- }
- void dfs1(int u, int fa, int depth) {
- f[u] = fa; dep[u] = depth; siz[u] = 1;
- for (int i = head[u]; i != -1; i = ex[i].nxt) {
- int v = ex[i].v;
- if (v == fa) continue;
- dfs1(v, u, depth + 1);
- siz[u] += siz[v];
- if (siz[v] > siz[son[u]]) son[u] = v;
- }
- }
- void dfs2(int u, int t) {
- top[u] = t;
- id[u] = ++tot;//标记dfs序
- rk[tot] = u;//序号tot对应的结点u
- if (!son[u]) return;
- dfs2(son[u], t);
- /*我们选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
- 一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
- for (int i = head[u]; i != -1; i = ex[i].nxt) {
- int v = ex[i].v;
- if (v != son[u] && v != f[u]) dfs2(v, v);//一个点位于轻链底端,那么它的top必然是它本身
- }
- }
- void update2(int x, int y, int z)//修改x到y路径的值
- {
- // printf("x=%d y=%d %d %d\n", x, y, top[x], top[y]);
- while (top[x] != top[y])//不在同一条链上
- {
- // printf("%d %d\n", id[top[x]], id[x]);
- if (dep[top[x]] < dep[top[y]]) swap(x, y);//x为深度大的链
- update(1, 1, n, id[top[x]], id[x], z);//x为深度大的链
- x = f[top[x]];//深度大的向上跳
- }
- if (dep[x] > dep[y]) swap(x, y); //这里x和y在同一条链
- // printf("id[%d]=%d id[%d]=%d\n", x, id[x], y, id[y]);
- update(1, 1, n, id[x], id[y], z); //x和y这条链的更新
- }
- int query2(int x, int y) {
- int ret = 0;
- while (top[x] != top[y]) {
- if (dep[top[x]] < dep[top[y]]) swap(x, y);
- ret = (ret + query(1, 1, n, id[top[x]], id[x]));
- x = f[top[x]];
- }
- if (dep[x] > dep[y]) swap(x, y);
- ret = (ret + query(1, 1, n, id[x], id[y]));
- return ret;
- }
- //------------------树链剖分结束-------------------//
- int main() {
- init();
- int m, x;
- scanf("%d%d", &n, &m);
- for (int i = 2; i <= n; i++) scanf("%d", &x), add(x, i);
- dfs1(1, -1, 1), dfs2(1, 1);
- build(1, 1, n);
- // for (int i = 1; i <= n; i++) printf("id[%d]=%d\n", i, id[i]);
- while (m--) {
- int l, r, c, ans = 0;
- scanf("%d%d%d", &l, &r, &c);
- // printf("l=%d r=%d c=%d\n", l, r, c);
- update2(r, l, 1);
- ans = max(ans, query2(c, l));
- ans = max(ans, query2(c, r));
- update(1, 1, n, 1, n, 0);
- update2(c, l, 1);
- ans = max(ans, query2(r, l));
- ans = max(ans, query2(r, c));
- update(1, 1, n, 1, n, 0);
- update2(r, c, 1);
- ans = max(ans, query2(l, c));
- ans = max(ans, query2(l, r));
- update(1, 1, n, 1, n, 0);
- printf("%d\n", ans);
- }
- return 0;
- }
D. Misha, Grisha and Underground 树链剖分的更多相关文章
- Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组
Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations ...
- 树链剖分 + 后缀数组 - E. Misha and LCP on Tree
E. Misha and LCP on Tree Problem's Link Mean: 给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. analyse: ...
- CF 504E Misha and LCP on Tree(树链剖分+后缀数组)
题目链接:http://codeforces.com/problemset/problem/504/E 题意:给出一棵树,每个结点上有一个字母.每个询问给出两个路径,问这两个路径的串的最长公共前缀. ...
- CF 504E Misha and LCP on Tree——后缀数组+树链剖分
题目:http://codeforces.com/contest/504/problem/E 树链剖分,把重链都接起来,且把每条重链的另一种方向的也都接上,在这个 2*n 的序列上跑后缀数组. 对于询 ...
- CF504E Misha and LCP on Tree(树链剖分+后缀树组)
1A真舒服. 喜闻乐见的树链剖分+SA. 一个初步的想法就是用树链剖分,把两个字符串求出然后hash+二分求lcp...不存在的. 因为考虑到这个字符串是有序的,我们需要把每一条重链对应的字符串和这个 ...
- CF504E Misha and LCP on Tree 后缀自动机+树链剖分+倍增
求树上两条路径的 LCP (树上每个节点代表一个字符) 总共写+调了6个多小时,终于过了~ 绝对是我写过的最复杂的数据结构了 我们对这棵树进行轻重链剖分,然后把所有的重链分正串,反串插入到广义后缀自动 ...
- Codeforces Round #425 (Div. 2) Misha, Grisha and Underground(LCA)
Misha, Grisha and Underground time limit per test 2 seconds memory limit per test 256 megabytes inpu ...
- Codeforecs Round #425 D Misha, Grisha and Underground (倍增LCA)
D. Misha, Grisha and Underground time limit per test 2 seconds memory limit per test 256 megabytes i ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
随机推荐
- CVE-2019-0193 远程命令执行-漏洞复现
0x01 漏洞简介 Apache Solr 是一个开源的搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.此次漏洞出现在Apache Solr的 ...
- Spring Cloud和eureka启动报错 解决版本依赖关系
导读 An attempt was made to call a method that does not exist. The attempt was made from the following ...
- 【翻译】创建String 使用“”还是构造函数(new String)
在java中创建String,通常有以下两种方法. String x = "abc"; String y = new String("abc"); 它们之间有什 ...
- Oracle NULL值
NULL值,用来描述记录中没有定义内容的字段值.在Oracle中,判断某个条件的值时,返回值可能是TRUE.FALSE或UNKNOWN. 如果查询一个列的值是否等于20,而该列的值为NULL,那么就是 ...
- stand up meeting 1/18/2016
part 组员 工作 工作耗时/h 明日计划 工作耗时/h UI 冯晓云 准备最后的发布和整个开发的整理总结 6 release ...
- Daily Scrum 12/18/2015
Process: Zhaoyang: Some IOS UI upgrade to increase the users' experience. Minlong: Build a restful s ...
- F - Make It Equal CodeForces - 1065C
题目大意:有n座塔,塔高h[i],每次给定高度H对他们进行削切,要求每次削掉的所有格子数不能超过k个,输出最少削几次才能使所有塔的高度相同. 思路一:差分+贪心 对于每一个高度h,用一个数组让1~h的 ...
- LCA基础 附例题(落谷)
https://www.luogu.org/problemnew/solution/P3379 LCA叫做最短公共祖先,用来求距离树上两个节点最近的公共点: 常用倍增算法: #include<i ...
- 14. 最长公共前缀----LeetCode
编写一个函数来查找字符串数组中的最长公共前缀. 如果不存在公共前缀,返回空字符串 "". 示例 1: 输入: ["flower","flow" ...
- Kaggle入门——泰坦尼克号生还者预测
前言 这个是Kaggle比赛中泰坦尼克号生存率的分析.强烈建议在做这个比赛的时候,再看一遍电源<泰坦尼克号>,可能会给你一些启发,比如妇女儿童先上船等.所以是否获救其实并非随机,而是基于一 ...