题目描述

Linux用户和OSX用户一定对软件包管理器不会陌生。通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安装所依赖的其它软件包),完成所有的配置。Debian/Ubuntu使用的apt-get,Fedora/CentOS使用的yum,以及OSX下可用的homebrew都是优秀的软件包管理器。

你决定设计你自己的软件包管理器。不可避免地,你要解决软件包之间的依赖问题。如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。现在你已经获得了所有的软件包之间的依赖关系。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环(若有m(m≥2)个软件包A1,A2,A3,…,Am,其中A1依赖A2,A2依赖A3,A3依赖A4,……,Am−1依赖Am,而Am依赖A1,则称这m个软件包的依赖关系构成环),当然也不会有一个软件包依赖自己。
现在你要为你的软件包管理器写一个依赖解决程序。根据反馈,用户希望在安装和卸载某个软件包时,快速地知道这个操作实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包),你的任务就是实现这个部分。注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0。

输入

输入文件的第1行包含1个正整数n,表示软件包的总数。软件包从0开始编号。

随后一行包含n−1个整数,相邻整数之间用单个空格隔开,分别表示1,2,3,…,n−2,n−1号软件包依赖的软件包的编号。
接下来一行包含1个正整数q,表示询问的总数。
之后q行,每行1个询问。询问分为两种:
installx:表示安装软件包x
uninstallx:表示卸载软件包x
你需要维护每个软件包的安装状态,一开始所有的软件包都处于未安装状态。对于每个操作,你需要输出这步操作会改变多少个软件包的安装状态,随后应用这个操作(即改变你维护的安装状态)。

输出

输出文件包括q行。

输出文件的第i行输出1个整数,为第i步操作中改变安装状态的软件包数。

样例输入

7
0 0 0 1 1 5
5
install 5
install 6
uninstall 1
install 4
uninstall 0

样例输出

3
1
3
2
3

提示

一开始所有的软件包都处于未安装状态。

安装 5 号软件包,需要安装 0,1,5 三个软件包。
之后安装 6 号软件包,只需要安装 6 号软件包。此时安装了 0,1,5,6 四个软件包。
卸载 1 号软件包需要卸载 1,5,6 三个软件包。此时只有 0 号软件包还处于安装状态。
之后安装 4 号软件包,需要安装 1,4 两个软件包。此时 0,1,4 处在安装状态。
最后,卸载 0 号软件包会卸载所有的软件包。
n=100000
q=100000
  每次询问和修改操作是混在一起的,设安装状态为1,未安装状态为0,每次安装查询点到根路径上0个数,并都修改为1;每次卸载查询子树中1个数,并都修改为0。直接dfs求出树剖序然后架在线段树上,每次边查询边修改。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
char ch[20];
int n,m;
int x;
int head[100010];
int to[100010];
int next[100010];
int f[100010];
int size[100010];
int top[100010];
int son[100010];
int sum[800010];
int a[800010];
int s[100010];
int t[100010];
int num;
int ans;
int tot;
void add(int x,int y)
{tot++;next[tot]=head[x];head[x]=tot;to[tot]=y;
}
void dfs(int x)
{size[x]=1;for(int i=head[x];i;i=next[i]){dfs(to[i]);size[x]+=size[to[i]];if(size[to[i]]>size[son[x]]){son[x]=to[i];}}
}
void dfs2(int x,int tp)
{s[x]=++num;top[x]=tp;if(son[x]){dfs2(son[x],tp);}for(int i=head[x];i;i=next[i]){if(to[i]!=son[x]){dfs2(to[i],to[i]);}}t[x]=num;
}
void pushup(int rt)
{sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int l,int r)
{int mid=(l+r)>>1;if(a[rt]==0){sum[rt<<1]=0;sum[rt<<1|1]=0;a[rt<<1]=0;a[rt<<1|1]=0;}if(a[rt]==1){sum[rt<<1]=mid-l+1;sum[rt<<1|1]=r-mid;a[rt<<1]=1;a[rt<<1|1]=1;}a[rt]=-1;
}
void change(int rt,int l,int r,int L,int R,int v)
{if(L<=l&&r<=R){a[rt]=v;sum[rt]=v*(r-l+1);return ;}pushdown(rt,l,r);int mid=(l+r)>>1;if(L<=mid){change(rt<<1,l,mid,L,R,v);}if(R>mid){change(rt<<1|1,mid+1,r,L,R,v);}pushup(rt);
}
int query(int rt,int l,int r,int L,int R,int v)
{if(L<=l&&r<=R){if(v==0){return r-l+1-sum[rt];}else{return sum[rt];}}pushdown(rt,l,r);int mid=(l+r)>>1;int res=0;if(L<=mid){res+=query(rt<<1,l,mid,L,R,v);}if(R>mid){res+=query(rt<<1|1,mid+1,r,L,R,v);}return res;
}
int main()
{memset(a,-1,sizeof(a));scanf("%d",&n);for(int i=1;i<n;i++){scanf("%d",&x);f[i+1]=x+1;add(x+1,i+1);}dfs(1);dfs2(1,1);scanf("%d",&m);for(int i=1;i<=m;i++){scanf("%s",ch);scanf("%d",&x);x++;ans=0;if(ch[0]=='i'){while(top[x]!=1){ans+=query(1,1,n,s[top[x]],s[x],0);change(1,1,n,s[top[x]],s[x],1);x=f[top[x]];}ans+=query(1,1,n,1,s[x],0);change(1,1,n,1,s[x],1);printf("%d\n",ans);}else{ans+=query(1,1,n,s[x],t[x],1);change(1,1,n,s[x],t[x],0);printf("%d\n",ans);}}
}

转载于:https://www.cnblogs.com/Khada-Jhin/p/9558841.html

BZOJ4196[Noi2015]软件包管理器——树链剖分+线段树相关推荐

  1. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1153  Solved: 421 [Submit][Sta ...

  2. BZOJ3862Little Devil I——树链剖分+线段树

    题目大意: 给一棵树,每条边可能是黑色或白色(起始都是白色),有三种操作: 1.将u到v路径上所有边颜色翻转(黑->白,白->黑) 2.将只有一个点在u到v路径上的边颜色翻转 3.查询u到 ...

  3. CodeForces - 160D Edges in MST(思维+tarjan/树链剖分+线段树)

    题目链接:点击查看 题目大意:给出一张 n 个点 m 条边组成的带权无向图,现在对于每条边来说,确定一下其分类: 一定是最小生成树上的边 可能是最小生成树上的边 一定不是最小生成树的边 题目分析:两种 ...

  4. CodeForces - 609E Minimum spanning tree for each edge(最小生成树+树链剖分+线段树/树上倍增)

    题目链接:点击查看 题目大意:给出一张 n 个点和 m 条边组成的无向图,现在询问包含每一条边的最小生成树 题目分析:考虑求解次小生成树的思路: 求出最小生成树 ans 枚举每一条非树边 ( u , ...

  5. P2486 [SDOI2011]染色(树链剖分+线段树)

    题干描述 输入描述 输出格式 对于每个询问操作,输出一行答案. 输入输出样例 输入 #1 复制 6 5 2 2 1 2 1 1 1 2 1 3 2 4 2 5 2 6 Q 3 5 C 2 1 1 Q ...

  6. BZOJ4127Abs——树链剖分+线段树

    题目描述 给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和 输入 第一行两个整数n和m,表示结点个数和操作数 ...

  7. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  8. HDU 2460 Network(双连通+树链剖分+线段树)

    HDU 2460 Network 题目链接 题意:给定一个无向图,问每次增加一条边,问个图中还剩多少桥 思路:先双连通缩点,然后形成一棵树,每次增加一条边,相当于询问这两点路径上有多少条边,这个用树链 ...

  9. BZOJ2325[ZJOI2011]道馆之战——树链剖分+线段树

    题目描述 口袋妖怪(又名神奇宝贝或宠物小精灵)红/蓝/绿宝石中的水系道馆需要经过三个冰地才能到达馆主的面前,冰地中 的每一个冰块都只能经过一次.当一个冰地上的所有冰块都被经过之后,到下一个冰地的楼梯才 ...

  10. YbtOJ-染色计划【树链剖分,线段树,tarjan】

    正题 题目大意 给出nnn个点的一棵树,每个点有个颜色aia_iai​,你每次可以选择一个颜色全部变成另一个颜色. 求最少多少次操作可以把一种颜色变成一个完整的连通块. 1≤k≤n≤2×1051\le ...

最新文章

  1. html javaScript 只能输入数字
  2. Linux c语言虚拟串口,利用socat和cutecom实现Linux虚拟串口通信
  3. 全球及中国金属粘合剂行业需求规模及产销前景分析报告2022-2027年
  4. 大智慧数据文件python_马克的Python学习笔记#模块和包 3
  5. Java学完后从业薪资怎么样?前景如何?
  6. ctrl键一直自动按住了_用好Ctrl键,年薪一两万
  7. 【.NET进程通信】初探.NET中进程间通信的简单的实现
  8. 华为不做黑寡妇,开源编译器,与友商共建安卓性能
  9. 从UnitedStack OS 1.0 Preview试用申请问卷调查学习OpenStack
  10. javascript arguments 特殊 对象
  11. 数据库订单表状态字段值设计的一些思考
  12. IOS中扩展机制Category和associative
  13. Shell总结(整理)
  14. tomcat设置编码为UTF-8
  15. Html常用正则表达式
  16. python ttf font weight_使用FontCreator将ttf字体制作多字重字体并打包为Magisk字体模块...
  17. 7z解压crc错误_rar文件解压缩失败解压末端出现错误的解决方法
  18. 金融学习之十——远期利率和远期利率协议
  19. 如何修改Windows上Docker的镜像源
  20. dos的cd命令输入cd d: 怎么不能切换到D盘了?

热门文章

  1. Educational Codeforces Round 12 C. Simple Strings 贪心
  2. C#调用C++的DLL函数另一则(delegate) z
  3. JAVA学习笔记--4.多线程编程 part1.背景知识和内存模型
  4. Jake Coco - Under The Covers, Vol. 2 {2011}
  5. Windows Server2003 sp2重装IIS后无法浏览asp.net网页解决方法
  6. const的用法,特别是用在函数后面
  7. 初识类(classstruct)及C/C++封装的差异
  8. 【转】接口测试Session/Cookie笔记(二)
  9. Docker 1.13 管理命令
  10. logging 模块记录日志