题解 P2146 【[NOI2015]软件包管理器】
题目大意
给你一棵树, 求一点到根的路径上有多少个未标记点并全标记, 和询问一个点的子树内有多少已标记点和撤销标记
解题方法
1: install 操作
这个操作是求一点到根的路径上有多少个未标记点并全标记, 这种操作可以用树链剖分来解决,将已标记的点的权值设为1, 求和即可
2.uninstall 操作
这个操作询问一个点的子树内有多少已标记点和撤销标记, 同理上面的方法就好了。
代码实现
---------------------------------------------
#include <bits/stdc++.h>
using namespace std;
template<class T>
inline void read(T &a){
T s = 0, w = 1;
char c = getchar();
while(c < '0' || c > '9') {if(c == '-') w = -1; c =getchar();}
while(c >= '0' && c <= '9') {s = (s << 1) + (s << 3) + (c ^ 48); c = getchar();}
a = s * w;
}
#define maxn 200100
#define maxm 200100
static int n, m;
static int net[maxm], to[maxm], head[maxm], tot;
inline void add(int x, int y){
net[++tot] = head[x], head[x] = tot, to[tot] = y;
}
/*-----------------------------------------------------------*/
static int fat[maxn], size[maxn], deep[maxn];
static int son[maxn];
void dfs1(int x, int fa){
fat[x] = fa;
size[x] = 1;
son[x] = 0;
deep[x] = deep[fa] + 1;
for (int i = head[x];i;i = net[i]){
int v = to[i];
if(v == fa) continue;
dfs1(v, x);
size[x] += size[v];
if(size[v] > size[son[x]]) son[x] = v;
}
}
static int tid[maxn], hhd[maxn], cnt, top[maxn];
void dfs2(int x, int t, int fa){
tid[x] = ++cnt; hhd[cnt] = x; top[x] = t;
if(!son[x]) return;
top[x] = t;
dfs2(son[x], t, x);
for (int i = head[x];i;i = net[i]){
int v = to[i];
if(v == fa || v == son[x]) continue;
dfs2(v, v, x);
}
}
/*-----------------------------------------*/
static int Sum[maxn * 8], lazy[maxn * 8];
#define ls rt << 1
#define rs rt << 1 | 1
inline void push_down(int rt, int l, int r){
int mid = (l + r) / 2;
Sum[ls] = (mid - l + 1) * lazy[rt];
Sum[rs] = (r - (mid + 1) + 1) * lazy[rt];
lazy[ls] = lazy[rt]; lazy[rs] = lazy[rt];
lazy[rt] = -1;
}
int ans = 0;
int Query(int rt, int l, int r, int L, int R){
if(L <= l && r <= R){
return Sum[rt];
}
else{
int mid = (l + r) / 2;
if(lazy[rt] != -1) push_down(rt, l, r);
int ans = 0;
if(L <= mid) ans += Query(ls, l, mid, L, R);
if(R > mid) ans += Query(rs, mid + 1, r, L, R);
Sum[rt] = Sum[ls] + Sum[rs];
return ans;
}
}
void Change(int rt, int l, int r, int L, int R, int d){
if(L <= l && r <= R){
Sum[rt] = (r - l + 1) * d;
lazy[rt] = d;
}
else{
int mid = (l + r) / 2;
if(lazy[rt] != -1) push_down(rt, l, r);
if(L <= mid) Change(ls, l , mid, L, R, d);
if(R > mid) Change(rs, mid + 1, r, L, R, d);
Sum[rt] = Sum[ls] + Sum[rs];
}
}
inline int Query_path(int x, int y){
int fx = top[x], fy = top[y];
int ans = 0;
while(fx != fy){
if(deep[x] < deep[y]) swap(x, y), swap(fx, fy);
ans += Query(1, 1, n, tid[fx], tid[x]);
x = fat[fx];
fx = top[x];
}
if(tid[x] < tid[y]) swap(x, y), swap(fx, fy);
ans += Query(1, 1, n, tid[y], tid[x]);
return ans;
}
inline void Change_path(int x, int y, int d){
int fx = top[x], fy = top[y];
int ans = 0;
while(fx != fy){
if(deep[x] < deep[y]) swap(x, y), swap(fx, fy);
Change(1, 1, n, tid[fx], tid[x], d);
x = fat[fx];
fx = top[x];
}
if(tid[x] < tid[y]) swap(x, y);
Change(1, 1, n, tid[y], tid[x], d);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("p2146.in","r", stdin);
freopen("p2146.out","w", stdout);
#endif
memset(lazy, -1, sizeof(lazy));
read(n);
for (int i = 1; i <= n-1; i++){
int x;
read(x);
add(x + 1, i + 1); add(i + 1, x + 1);
}
read(m);
dfs1(1, 0);
dfs2(1,1,0);
// build(1, 1, n);
for (int i = 1; i <= m; i++){
string s;
cin>>s;
// cout<<s<<endl;
if(s == "install"){
int x;
read(x); x++;
// printf("ss %d\n",i);
int ans = Query_path(1, x);
printf("%d\n", deep[x] - ans);
Change_path(1, x, 1);
}
else{
int x = 0;
read(x); x++;
int ans = Query(1, 1, n, tid[x], tid[x] + size[x] - 1);
printf("%d\n", ans);
Change(1, 1, n, tid[x], tid[x] + size[x] - 1, 0);
}
}
return 0;
}
题解 P2146 【[NOI2015]软件包管理器】的更多相关文章
- 题解 P2146 [NOI2015]软件包管理器
P2146 [NOI2015]软件包管理器 感觉代码比其他题解更简洁qwq 树链剖分模板题 install x:将1~x的路径上的节点全部变成1(安装x需要先安装1~x) uninstall x:将x ...
- 【题解】NOI2015软件包管理器
[题解][P2146 NOI2015]软件包管理器 实际上就是树链剖分板子题. 对于\(install\)操作,直接查询它到\(0\)节点有多少已经安装了的,再用总数减去它. 对于\(uninstal ...
- 洛谷 P2146 [NOI2015]软件包管理器 解题报告
P2146 [NOI2015]软件包管理器 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软 ...
- 洛谷 P2146 [NOI2015]软件包管理器 树链剖分
目录 题面 题目链接 题目描述 输入输出格式 输入格式: 输出格式: 输入输出样例 输入样例#1: 输出样例#1: 输入样例#2: 输出样例#2: 说明 说明 思路 AC代码 总结 题面 题目链接 P ...
- P2146 [NOI2015]软件包管理器
题目链接:https://www.luogu.org/problemnew/show/P2146 题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安 ...
- 洛谷 P2146 [NOI2015]软件包管理器 (树链剖分模板题)
题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...
- 【luogu P2146 [NOI2015]软件包管理器】 题解
题目链接:https://www.luogu.org/problemnew/show/P2146 变量名真毒瘤 我真的再也不把l,left,r,right弄反了 反向思维更好做一些 #include ...
- 洛谷P2146 [NOI2015]软件包管理器 题解 树链剖分+线段树
题目链接:https://www.luogu.org/problem/P2146 本题涉及算法: 树链剖分: 线段树(区间更新及求和,涉及懒惰标记) 然后对于每次 install x ,需要将 x 到 ...
- 【题解】Luogu P2146 [NOI2015]软件包管理器
题面:https://www.luogu.org/problemnew/lists?name=2146 这道题要用树链剖分,我博客里有对树链剖分的详细介绍 这道题就是树链剖分的模板,详细解释见程序. ...
- 洛谷P2146 [NOI2015]软件包管理器
https://www.luogu.org/problemnew/show/P2146 传送门 简单的树链剖分......维护下当前安装了多少个包......修改后查询下就行了......附上极其丑陋 ...
随机推荐
- Hadoop3集群搭建之——配置ntp服务
上篇: Hadoop3集群搭建之——虚拟机安装 Hadoop3集群搭建之——安装hadoop,配置环境 下篇: Hadoop3集群搭建之——hive安装 Hadoop3集群搭建之——hbase安装及简 ...
- Python脚本语言第一行的写法
脚本语言的第一行,目的就是指出,你想要你的这个文件中的代码用什么可执行程序去运行它,就这么简单 #!/usr/bin/python是告诉操作系统执行这个脚本的时候,调用/usr/bin下的python ...
- Java日期时间使用总结[转载]
Java日期时间使用总结 一.Java中的日期概述 日期在Java中是一块非常复杂的内容,对于一个日期在不同的语言国别环境中,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式 ...
- js生成条形码插件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 2.Early Education of Children 儿童的早期教育
2.Early Education of Children 儿童的早期教育 (1) In bringing up children,every parent watches eagerly the c ...
- 开发.Net Script 模板-MyGeneration (翻译)
原文信息 原文地址 原文作者信息 Justin Greenwood MyGeneration Software http://www.mygenerationsoftware.com/ October ...
- Android拖动和缩放
拖拽和缩放 多点触控的理论学完了之后,这里开始实践.本节主要介绍使用onTouchEvent()方法处理触控事件. 拖动一个对象 如果你使用的是Android 3.0或者之后的系统,那么你可以使用内置 ...
- git windows下载安装 (git命令)
Set up git At the heart of GitHub is an open source version control system (VCS) called Git. Git is ...
- Linq动态查询与模糊查询 ---转
Linq动态查询与模糊查询(带源码示例) 继LINQ动态组合查询PredicateExtensions讲解 ----- 在用上面的方法时遇到了些问题 解决 LINQ to Entities 不支持 L ...
- curl工具介绍和常用命令
curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被广泛应用在Unix.Linux发行版中,并且有DOS和Win32.Win64的移植版本.curl是一个利用URL规则在命令行下工作的文 ...