题意

思路:直接树链剖分,用线段树维护即可,算是树剖的经典题目吧。

代码:

#include <bits/stdc++.h>
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
using namespace std;
const int maxn = 100010;
int head[maxn], Next[maxn * 2], ver[maxn * 2];
int sz[maxn], son[maxn], d[maxn], dfn[maxn], top[maxn], f[maxn];
int tot, cnt;
int n;
struct SegmentTree {
int val, lz;
int l, r;
};
SegmentTree tr[maxn * 4];
void add(int x, int y) {
ver[++tot] = y;
Next[tot] = head[x];
head[x] = tot;
}
void dfs1(int x, int fa = -1) {
sz[x] = 1;
f[x] = fa;
int mx = 0;
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == fa) continue;
d[y] = d[x] + 1;
dfs1(y, x);
sz[x] += sz[y];
if(sz[y] > mx) {
mx = sz[y];
son[x] = y;
}
}
}
void dfs2(int x, int fa, int t) {
dfn[x] = ++cnt;
top[x] = t;
if(son[x]) dfs2(son[x], x, t);
for (int i = head[x]; i; i = Next[i]) {
int y = ver[i];
if(y == fa || y == son[x]) continue;
dfs2(y, x, y);
}
}
void pushup(int o) {
tr[o].val = tr[ls(o)].val + tr[rs(o)].val;
}
void maintain(int o, int val) {
tr[o].val = val * (tr[o].r - tr[o].l + 1);
tr[o].lz = val;
}
void pushdown(int o) {
if(tr[o].lz != -1) {
maintain(ls(o), tr[o].lz);
maintain(rs(o), tr[o].lz);
tr[o].lz = -1;
}
}
void build(int o, int l, int r) {
tr[o].l = l, tr[o].r = r;
if(l == r) {
tr[o].val = 0;
tr[o].lz = -1;
return;
}
int mid = (l + r) >> 1;
build(ls(o), l, mid);
build(rs(o), mid + 1, r);
pushup(o);
}
void update(int o, int l, int r, int ql, int qr, int val) {
if(l >= ql && r <= qr) {
tr[o].val = (r - l + 1) * val;
tr[o].lz = val;
return;
}
pushdown(o);
int mid = (l + r) >> 1;
if(ql <= mid) update(ls(o), l, mid, ql, qr, val);
if(qr > mid) update(rs(o), mid + 1, r, ql, qr, val);
pushup(o);
}
int query(int o, int l, int r, int ql, int qr) {
if(l >= ql && r <= qr) {
return tr[o].val;
}
pushdown(o);
int mid = (l + r) >> 1, ans = 0;
if(ql <= mid) ans += query(ls(o), l, mid , ql, qr);
if(qr > mid) ans += query(rs(o), mid + 1, r, ql, qr);
return ans;
}
int solve(int x) {
int ans = 0, st = x;
while(x != -1) {
ans += query(1, 1, n, dfn[top[x]], dfn[x]);
x = f[top[x]];
}
return d[st] - d[0] + 1 - ans;
}
void update1(int x, int val) {
while(x != -1) {
update(1, 1, n, dfn[top[x]], dfn[x], val);
x = f[top[x]];
}
}
char s[110];
int main() {
int x, m;
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d", &x);
add(x, i);
add(i, x);
}
f[0] = -1;
build(1, 1, n);
dfs1(0);
dfs2(0, -1, 0);
scanf("%d", &m);
while(m--) {
scanf("%s", s + 1);
if(s[1] == 'i') {
scanf("%d", &x);
int tmp = query(1, 1, n, dfn[x], dfn[x]);
if(tmp == 1) {
printf("0\n");
continue;
}
printf("%d\n", solve(x));
update1(x, 1);
} else {
scanf("%d", &x);
int tmp = query(1, 1, n, dfn[x], dfn[x]);
if(tmp == 0) {
printf("0\n");
continue;
}
printf("%d\n", query(1, 1, n, dfn[x], dfn[x] + sz[x] - 1));
update(1, 1, n, dfn[x], dfn[x] + sz[x] - 1, 0);
}
}
}

  

洛谷P2146 树链剖分的更多相关文章

  1. 【算法学习】【洛谷】树链剖分 & P3384 【模板】树链剖分 P2146 软件包管理器

    刚学的好玩算法,AC2题,非常开心. 其实很早就有教过,以前以为很难就没有学,现在发现其实很简单也很有用. 更重要的是我很好调试,两题都是几乎一遍过的. 介绍树链剖分前,先确保已经学会以下基本技巧: ...

  2. 洛谷P3384 树链剖分

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x ...

  3. 洛谷 P3384 树链剖分(模板题)

    题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式 ...

  4. 【树链剖分】洛谷P3379 树链剖分求LCA

    题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...

  5. 洛谷 P3384树链剖分 题解

    题面 挺好的一道树剖模板: 首先要学会最模板的树剖: 然后这道题要注意几个细节: 初始化时,seg[0]=1,seg[root]=1,top[root]=root,rev[1]=root; 在线段树上 ...

  6. 洛谷 [P3384] 树链剖分 模版

    支持各种数据结构上树,注意取膜. #include <iostream> #include <cstring> #include <algorithm> #incl ...

  7. 树链剖分详解(洛谷模板 P3384)

    洛谷·[模板]树链剖分 写在前面 首先,在学树链剖分之前最好先把 LCA.树形DP.DFS序 这三个知识点学了 emm还有必备的 链式前向星.线段树 也要先学了. 如果这三个知识点没掌握好的话,树链剖 ...

  8. 【模板时间】◆模板·II◆ 树链剖分

    [模板·II]树链剖分 学长给我讲树链剖分,然而我并没有听懂,还是自学有用……另外感谢一篇Blog +by 自为风月马前卒+ 一.算法简述 树链剖分可以将一棵普通的多叉树转为线段树计算,不但可以实现对 ...

  9. 洛谷P2146 [NOI2015]软件包管理器 题解 树链剖分+线段树

    题目链接:https://www.luogu.org/problem/P2146 本题涉及算法: 树链剖分: 线段树(区间更新及求和,涉及懒惰标记) 然后对于每次 install x ,需要将 x 到 ...

随机推荐

  1. hdu 1220 容斥

    http://acm.hdu.edu.cn/showproblem.php?pid=1220 Cube Time Limit: 2000/1000 MS (Java/Others)    Memory ...

  2. Https---SSL协议

    ssl协议的起源和历史我就不再多说了,就是那个Netscape 网景公司开发的,它的作用主要是提供了一种安全传输方式,我们知道网上有很多的时候需要我们去输入用户名和密码,那么假设我们自己的电脑防病毒还 ...

  3. LINUX CENTOS关机与重启命令详解

    Linux centos重启命令: 1.reboot 2.shutdown -r now 立刻重启(root用户使用) 3.shutdown -r 10 过10分钟自动重启(root用户使用) 4.s ...

  4. sql生成excel

    gosp_configure 'show advanced options',1reconfiguregosp_configure 'xp_cmdshell',1reconfiguregoEXEC m ...

  5. oracle 索引(3)

    位图索引 位图索引非常适合于决策支持系统(Decision Support System,DSS)和数据仓库,它们不应该用于通过事务处理应用程序访问的表.它们可以使用较少到中等基数(不同值的数量)的列 ...

  6. Java进阶知识点3:更优雅地关闭资源 - try-with-resource及其异常抑制

    一.背景 我们知道,在Java编程过程中,如果打开了外部资源(文件.数据库连接.网络连接等),我们必须在这些外部资源使用完毕后,手动关闭它们.因为外部资源不由JVM管理,无法享用JVM的垃圾回收机制, ...

  7. java web工程启动socket服务

    1.新建web工程 2.自定义类 实现ServletContextListener 接口 在contextInitialized方法中启动socket服务的线程 在contextDestroyed方法 ...

  8. freemarker实现第一个HelloWorld

    第一步:引入freemarker jar包 第二步:创建templates下的test01.ftl 第三步:在web.xml下 第四步:编写后台代码 package com.wisezone.test ...

  9. SSL/TLS捕包分析

    一.基本概念 SSL:(Secure Socket Layer,安全套接字层),位于可靠的面向连接的网络层协议和应用层协议之间的一种协议层.SSL通过互相认证.使用数字签名确保完整性.使用加密确保私密 ...

  10. Oracle hash分区的秘密

    转自:http://www.hellodb.net/2009/12/hash_partition.html 在面试时经常会问一个问题,请列举出hash在数据库内部的应用,hash的原理虽然简单,但是它 ...