描述


http://www.lydsy.com/JudgeOnline/problem.php?id=4196

给出一棵树,树上点权为0或1.u权值为1的条件是从根节点到u路径上的所有点权值都为1.u权值为0的条件为u的子树中所有节点权值都为0,进行如下两种操作:

1.install u.将u改为1.

2.uninstall u.将u改为0.

每次操作输出执行此操作需要改动的点的个数,并进行改动操作.

4196: [Noi2015]软件包管理器

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 991  Solved: 572
[Submit][Status][Discuss]

Description

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。

Input

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

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

Output

输出文件包括q行。

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

Sample Input

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

Sample Output

3
1
3
2
3

HINT

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

安装 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

Source

分析


两种操作:路径操作和子树操作.树链剖分用线段树维护.

路径操作:直接向上一直走到根节点即可.

子树操作:注意到树链剖分结束后,对于节点u,u的子树中的所有节点的tid值都大于tid[u],因为它们是在u之后访问的,并且子树中所有点的tid值是连续的,因为从u点开始,直到返回u点,访问整个子树的时候,tid值每次+1,故值时连续的.所以可以记录子树中的tid的最大值,即将整个子树转化为区间后的区间右端点(左端点为u).那进行子树操作的时候进行区间操作就可以了.比路径操作更简单.

注意:

1.线段树操作的时候要注意l<=r(tid[top[u]]要卸载tid[u]的前面,因为tid[top[u]]<=tid[u])(好像这个地方错了不止一次了= =).

ps.

1.从这次开始都用静态链表来代替vector了,讲真比vector快= =.做的时候结构体中放原本放在vector中的参量,再多放一个next,结构体数组g的大小为边的数量,再开一个大小为点的数量的head数组,head[u]用来代表从u出发的边中的第一条边在结构体数组g中编号.

  1 #include <cstdio>
  2 #include <algorithm>
  3
  4 using namespace std;
  5
  6 const int maxn=100000+5;
  7
  8 int n,q;
  9 int dep[maxn];
 10 int prt[maxn];
 11 int size[maxn];
 12 int son[maxn];
 13 int top[maxn];
 14 int tid[maxn];
 15 int rev_tid[maxn];
 16 int r[maxn];
 17
 18 struct Edge{
 19     int head[maxn];
 20     struct edge{
 21         int to,next;
 22         edge(){}
 23         edge(int a,int b):to(a),next(b){}
 24     }g[maxn];
 25
 26     void insert(int from,int to,int id){
 27         g[id]=edge(to,head[from]);
 28         head[from]=id;
 29     }
 30 }G;
 31
 32 struct Segment_Tree{
 33     struct node{
 34         int l,r,x,s;
 35     }a[4*maxn];
 36
 37     void build_tree(int l,int r,int k){
 38         a[k].l=l; a[k].r=r; a[k].x=0; a[k].s=0;
 39         if(l==r) return;
 40         int mid=l+(r-l)/2;
 41         build_tree(l,mid,2*k); build_tree(mid+1,r,2*k+1);
 42     }
 43
 44     inline void push_down(int k)
 45     {
 46         if(a[k].s!=-1){
 47             a[2*k].s=a[k].s; a[2*k].x=a[k].s?a[2*k].r-a[2*k].l+1:0;
 48             a[2*k+1].s=a[k].s; a[2*k+1].x=a[k].s?a[2*k+1].r-a[2*k+1].l+1:0;
 49         }
 50     }
 51
 52     inline void push_up(int k)
 53     {
 54         a[k].x=a[2*k].x+a[2*k+1].x;
 55         a[k].s=(a[2*k].s==a[2*k+1].s&&a[2*k].s!=-1)?a[2*k].s:-1;
 56     }
 57
 58     int search(int l,int r,int k,int t){
 59         if(a[k].l==l&&a[k].r==r){
 60             int ans=t?a[k].x:r-l+1-a[k].x;
 61             a[k].s=t?0:1;
 62             a[k].x=t?0:r-l+1;
 63             return ans;
 64         }
 65         int mid=a[k].l+(a[k].r-a[k].l)/2;
 66         push_down(k);
 67         int ans;
 68         if(r<=mid) ans=search(l,r,2*k,t);
 69         else if(l>mid) ans=search(l,r,2*k+1,t);
 70         else ans=search(l,mid,2*k,t)+search(mid+1,r,2*k+1,t);
 71         push_up(k);
 72         return ans;
 73     }
 74 }T;
 75
 76
 77 void find_h_e(int u,int p,int d){
 78     prt[u]=p; dep[u]=d; size[u]=1;
 79     int max_size=0;
 80     for(int i=G.head[u];i;i=G.g[i].next){
 81         int v=G.g[i].to;
 82         find_h_e(v,u,d+1);
 83         size[u]+=size[v];
 84         if(size[v]>max_size){
 85             max_size=size[v];
 86             son[u]=v;
 87         }
 88     }
 89 }
 90
 91 void conect_h_e(int u,int anc,int &k){
 92     top[u]=anc; tid[u]=++k; rev_tid[k]=u;
 93     if(son[u]) conect_h_e(son[u],anc,k);
 94     for(int i=G.head[u];i;i=G.g[i].next){
 95         int v=G.g[i].to;
 96         if(v!=son[u]){
 97             conect_h_e(v,v,k);
 98         }
 99     }
100     r[u]=rev_tid[k];
101 }
102
103 int get_sum1(int u){
104     int sum_now=0;
105     while(top[u]!=0){
106         sum_now+=T.search(tid[top[u]],tid[u],1,0);
107         u=prt[top[u]];
108     }
109     sum_now+=T.search(1,tid[u],1,0);
110     return sum_now;
111 }
112
113 int get_sum2(int u){return T.search(tid[u],tid[r[u]],1,1);}
114
115 void solve(){
116     scanf("%d",&q);
117     for(int i=1;i<=q;i++){
118         char c[15]; scanf("%s",c);
119         int u; scanf("%d",&u);
120         if(c[0]=='i') printf("%d\n",get_sum1(u));
121         else printf("%d\n",get_sum2(u));
122
123     }
124 }
125
126 void init(){
127     scanf("%d",&n);
128     for(int i=1;i<n;i++){
129         int from;
130         scanf("%d",&from);
131         G.insert(from,i,i);
132     }
133 }
134
135 int main(){
136 #ifndef ONLINE_JUDGE
137     freopen("3.in","r",stdin);
138     freopen("3.out","w",stdout);
139 #endif
140     init();
141     find_h_e(0,0,0);
142     int k=0;
143     conect_h_e(0,0,k);
144     T.build_tree(1,n,1);
145     solve();
146 #ifndef ONLINE_JUDGE
147     fclose(stdin);
148     fclose(stdout);
149     system("3.out");
150 #endif
151     return 0;
152 }
153
154  

View Code

转载于:https://www.cnblogs.com/Sunnie69/p/5477191.html

BZOJ_4196_[NOI2015]_软件包管理器_(树链剖分)相关推荐

  1. 软件包管理器(树链剖分)

    Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个软件包的安 ...

  2. 【BZOJ4196】【codevs4621】软件包管理器,树链剖分练习

    传送门1 传送门2 写在前面:感冒,在家休养,已陷入动物城不能自拔 思路:真的是莫名其妙就A了--加了个lazy标记什么的而且用了一些奇怪姿势的线段树?删一个包就是对它的子树进行统计,计算有多少个已安 ...

  3. 【NOI2015】软件包管理器

    NOI难得的水题,话说还是T2诶--又学到了线段树的一种新的魔性使用 看sxysxy大神的代码才写出来的,sxysxy_orz 原题: Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包 ...

  4. 树链剖分中的重链剖分

    更多文章可以在本人的个人小站:https://kaiserwilheim.github.io 查看. 转载请注明出处. 引言 树链剖分(简称"树剖",又称"重链剖分&qu ...

  5. NOI2015 Day1 T2 软件包管理器 树链剖分

    NKOJ3423 NOI2015 软件包管理器 时间限制 : 20000 MS 空间限制 : 524288 KB 问题描述 Linux用户和OS X用户一定对软件包管理器不会陌生.通过软件包管理器,你 ...

  6. BZOJ4196[Noi2015]软件包管理器——树链剖分+线段树

    题目描述 Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行命令安装某一个软件包,然后软件包管理器会帮助你从软件源下载软件包,同时自动解决所有的依赖(即下载安装这个 ...

  7. [Bzoj4196] [NOI2015] 软件包管理器 [树链剖分,线段树]

    题解摘要:树链剖分后用线段树区间查询修改,对于安装软件,将改点到根的路径全部变为1,对于卸载软件,将子树清空.注意边界,编号是从0开始的,容易漏掉树根. 第一次写树剖- 1 #include < ...

  8. [NOI2015]软件包管理器

    4621 [NOI2015]软件包管理器  题目等级 : 钻石 Diamond 题目描述 Description Linux用户和OSX用户一定对软件包管理器不会陌生.通过软件包管理器,你可以通过一行 ...

  9. 洛谷P2146DTOJ2409 [NOI2015]软件包管理器

    洛谷P2146&&DTOJ2409 [NOI2015]软件包管理器 题目 题目描述 输入格式 输出格式 样例 样例输入1 样例输出1 样例输入2 样例输出2 数据范围与提示 样例1说明 ...

  10. BZOJ4196:[NOI2015]软件包管理器——题解

    http://www.lydsy.com/JudgeOnline/problem.php?id=4196 https://www.luogu.org/problemnew/show/P2146 你决定 ...

最新文章

  1. 趣学python编程第六章答案_Python核心编程-第六章-习题
  2. 回溯算法和递归算法_回溯算法:递归和搜索示例说明
  3. php splqueue 5.5安装,解析PHP标准库SPL数据结构
  4. jsonp模拟获取百度搜索相关词汇
  5. 资源 ACCP-S1 BOOK3开发工具的下载
  6. 使用Android Studio 进行NDK开发和调试
  7. 【算法】算法求出2个超大正数相加
  8. win32开发(鼠标)
  9. Gym - 102163M
  10. cad插件_CAD插件常青藤3.0
  11. 国二c语言题库 word,国家二级计算机考试MS-Office历年真题题库及答案
  12. 14-基于51单片机的声音分贝测量与显示仿真
  13. nginx正向代理反向代理负载均衡
  14. null 和 undefined 的区别
  15. python图形包是什么_介绍Python 图形计算工具包
  16. WPF中的自定义控件模板
  17. 计算机的屏幕保护怎样开启,win10如何关闭和开启屏幕保护
  18. 喜欢计算机专业的理由英语作文,计算机专业英文自我评价范文
  19. matlab——灰色预测
  20. vue2 通过 axios  访问koa2,从mysql 拿到数据更新vue2中的内容

热门文章

  1. 如何格式化用过的磁带,让他被新磁带机重复利用
  2. HTML Text Editor
  3. 水晶报表2008部署
  4. dcopserver出错解决办法
  5. 夯实Java基础(八)——代码块
  6. datalist 给输入框绑定文本提示(大部分浏览器不支持)
  7. 【转】Maven 手动添加 JAR 包到本地仓库
  8. 通过反射调用方法会大大降低性能
  9. 再次理解HTTP请求过程[概念原理篇]
  10. X86平台下基于grub2+busybo+linux-2.6.36制作linux系统