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 ...
随机推荐
- 数据结构和算法(Golang实现)(23)排序算法-归并排序
归并排序 归并排序是一种分治策略的排序算法.它是一种比较特殊的排序算法,通过递归地先使每个子序列有序,再将两个有序的序列进行合并成一个有序的序列. 归并排序首先由著名的现代计算机之父John_von_ ...
- Thinking in Java,Fourth Edition(Java 编程思想,第四版)学习笔记(十四)之Type Information
Runtime type information (RTTI) allow you to discover and use type information while a program is ru ...
- Delphi Unicode转中文
function UniCode2GB(S : String):String;Var I: Integer;beginI := Length(S);while I >=4 do begintry ...
- python 3 的解释器
前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者:Yangtze PS:如有需要Python学习资料的小伙伴可以加点击下 ...
- 2019CCPC-江西省赛(重现赛)- 感谢南昌大学
A题: 题意: 给你两棵树,然后用一条边将这两棵树连接起来,然后计算 每两点之间的距离,然后求和,问这个和的最小值. 思路:根据重心的性质,树上的所有点到重心的距离最短,因此我们找到两棵树的重心,然后 ...
- Python实现按键精灵(一)-键鼠操作
需要安装 pywin32库 pip install pywin32 import win32api import time #鼠标移动 def mouse_move(x,y): win32api.Se ...
- BUU刷题01
[安洵杯 2019]easy_serialize_php 直接给了源代码 <?php $function = @$_GET['f']; function filter($img){ $filte ...
- Springboot:IDEA重调安装依赖窗口(二)
Settings-Plugins 搜索Editstarters: 安装完插件 重启idea: 查看安装是否成功: 在pom.xml 右键: 选择热部署依赖 点击ok进行自动装配: 热部署依赖环境已经配 ...
- Java IO基础--File常用操作(递归)
File中经常会使用递归方法打印属性结构.统计文件夹下文件个数.子文件夹个数以及文件大小,可以作为递归的应用练习. 递归的写法,百度一搜一大堆,这里我使用对javabean方式封装了一下: packa ...
- JS静态变量和静态函数
本文链接:https://blog.csdn.net/u012790503/article/details/46278521 function A(){this.id = "我是AA&quo ...