【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理

【题目大意】

如果软件包A依赖软件包B,那么安装软件包A以前,必须先安装软件包B。同时,如果想要卸载软件包B,则必须卸载软件包A。而且,由于你之前的工作,除0号软件包以外,在你的管理器当中的软件包都会依赖一个且仅一个软件包,而0号软件包不依赖任何一个软件包。依赖关系不存在环。求出在安装和卸载某个软件包时,实际上会改变多少个软件包的安装状态(即安装操作会安装多少个未安装的软件包,或卸载操作会卸载多少个已安装的软件包。(注意,安装一个已安装的软件包,或卸载一个未安装的软件包,都不会改变任何软件包的安装状态,即在此情况下,改变安装状态的软件包数为0)

【思路】

裸的树剖...然而我发现我写错了区间覆盖的线段树,要设置两个标记,一个记录该区间是否需要修改,另一个记录该区间覆盖的值。

话说BZOJ要用printf否则会RE,我怎么不长记性呢………

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<vector>
  6 #define lson l,m,rt<<1
  7 #define rson m+1,r,rt<<1|1
  8 using namespace std;
  9 const int MAXN=100000+50;
 10 const int rt=0;
 11 vector<int> E[MAXN];
 12 int n;
 13 int fa[MAXN],dep[MAXN],hson[MAXN],size[MAXN];
 14 int cnt=0,top[MAXN],pos[MAXN];
 15 int sum[MAXN<<3],add[MAXN<<3],change[MAXN<<3];
 16
 17 //树链剖分部分
 18 void addedge(int u,int v)
 19 {
 20     E[u].push_back(v);
 21 }
 22
 23 void dfs1(int u,int father,int depth)
 24 {
 25     fa[u]=father;
 26     dep[u]=depth;
 27     size[u]=1;
 28     hson[u]=-1;
 29     for (int i=0;i<E[u].size();i++)
 30     {
 31         int to=E[u][i];
 32         dfs1(to,u,depth+1);
 33         size[u]+=size[to];
 34         if (hson[u]==-1 || size[to]>size[hson[u]]) hson[u]=to;
 35     }
 36 }
 37
 38 void dfs2(int u,int t)
 39 {
 40     pos[u]=++cnt;
 41     top[u]=t;
 42     if (hson[u]!=-1) dfs2(hson[u],t);
 43     for (int i=0;i<E[u].size();i++)
 44     {
 45         int to=E[u][i];
 46         if (to!=hson[u]) dfs2(to,to);
 47     }
 48 }
 49
 50 //线段树部分
 51 void build()
 52 {
 53     memset(sum,0,sizeof(sum));
 54     memset(add,0,sizeof(add));
 55 }
 56
 57 void pushup(int rt)
 58 {
 59     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 60 }
 61
 62 void pushdown(int rt,int m)
 63 {
 64     if (change[rt])
 65     {
 66         change[rt<<1]=change[rt<<1|1]=1;
 67         add[rt<<1]=add[rt];
 68         add[rt<<1|1]=add[rt];
 69         sum[rt<<1]=add[rt]*(m-(m>>1));
 70         sum[rt<<1|1]=add[rt]*(m>>1);
 71         add[rt]=change[rt]=0;
 72     }
 73 }
 74
 75 int query_sum(int L,int R,int l,int r,int rt)
 76 {
 77     if (L<=l && r<=R) return sum[rt];
 78     pushdown(rt,r-l+1);
 79     int m=(l+r)>>1;
 80     int ret=0;
 81     if (m>=L) ret+=query_sum(L,R,lson);
 82     if (m<R) ret+=query_sum(L,R,rson);
 83     pushup(rt);
 84     return ret;
 85 }
 86
 87 void modify(int L,int R,int l,int r,int rt,int x)
 88 {
 89     if (L<=l && r<=R)
 90     {
 91         change[rt]=1;
 92         add[rt]=x;
 93         sum[rt]=(r-l+1)*x;
 94         return;
 95     }
 96     pushdown(rt,r-l+1);
 97     int m=(l+r)>>1;
 98     if (m>=L) modify(L,R,lson,x);
 99     if (m<R) modify(L,R,rson,x);
100     pushup(rt);
101 }
102
103 //树链剖分查询部分
104 int install(int x,int y)
105 {
106     int ret=dep[x],f1=top[x],f2=top[y];
107     while (f1!=f2)
108     {
109         ret-=query_sum(pos[f1],pos[x],1,n,1);
110         modify(pos[f1],pos[x],1,n,1,1);
111         x=fa[f1];
112         f1=top[x];
113     }
114     ret-=query_sum(pos[y],pos[x],1,n,1);
115     modify(pos[y],pos[x],1,n,1,1);
116     return (ret);
117 }
118
119 int uninstall(int x)
120 {
121     int ret=query_sum(pos[x],pos[x]+size[x]-1,1,n,1);
122     modify(pos[x],pos[x]+size[x]-1,1,n,1,0);
123     return ret;
124 }
125
126
127 //读入部分
128 void init()
129 {
130     scanf("%d",&n);
131     for (int i=1;i<n;i++)
132     {
133         int tmp;
134         scanf("%d",&tmp);
135         addedge(tmp,i);
136     }
137     dfs1(0,0,1);
138     dfs2(0,0);
139 }
140
141 void get_ans()
142 {
143     memset(sum,0,sizeof(sum));
144     memset(change,0,sizeof(change));
145     memset(add,0,sizeof(add));
146     int q;
147     scanf("%d",&q);
148     for (int i=0;i<q;i++)
149     {
150         char str[25];
151         int x;
152         scanf("%s%d",str,&x);
153         if (str[0]==‘i‘) printf("%d\n",install(x,rt));
154             else if (str[0]==‘u‘) printf("%d\n",uninstall(x));
155     }
156 }
157
158 int main()
159 {
160     init();
161     build();
162     get_ans();
163     return 0;
164 }
时间: 2024-08-17 20:00:59

【树链剖分(区间线段树)】BZOJ4196-[NOI2015]软件包管理的相关文章

bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status][Discuss] Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[

HDU - 3966 Aragorn&#39;s Story(树链剖分入门+线段树)

HDU - 3966 Aragorn's Story Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description Our protagonist is the handsome human prince Aragorn comes from The Lord of the Rings. One day Aragorn finds a lot of ene

poj 3237 Tree(树链剖分,线段树)

Tree Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 7268   Accepted: 1969 Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with

bzoj 1036 [ZJOI2008]树的统计Count(树链剖分,线段树)

1036: [ZJOI2008]树的统计Count Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 10677  Solved: 4313[Submit][Status][Discuss] Description 一 棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

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

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

bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)

3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 876  Solved: 446[Submit][Status][Discuss] Description S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足 从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰.为了方便,我们用不同的正整数代表 各种宗教,  S国的居民常常旅行.旅行时他们总

树链剖分处理+线段树解决问题 HDU 5029

http://acm.split.hdu.edu.cn/showproblem.php?pid=5029 题意:n个点的树,m次操作.每次操作输入L,R,V,表示在[L,R]这个区间加上V这个数字.比如[1,2]加上1,[1,3]加上1,那么1这个点就是{1,1},2也是{1,1},3是{1}.全部操作操作完之后,输出每个点中,最多的那个数字有几个.如果有相同的数字,就输出最小的那个数.比如{1,1,2,2},就输出1. 思路:树链剖分拍成链,然后通过找LCA,来离线预处理,然后最后通过离线暴力

cogs 1583. [POJ 3237] 树的维护 树链剖分套线段树

1583. [POJ 3237] 树的维护 ★★★★   输入文件:maintaintree.in   输出文件:maintaintree.out   简单对比时间限制:5 s   内存限制:128 MB [题目描述] 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1到N-1.每一条边有一个权值.然后你要在树上执行一系列指令.指令可以是如下三种之一: CHANGE i v:将第i条边的权值改成v. NEGATE a b:将点a到点b路径上所有边的权值变成其相反数. QUERY a b

ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat (树链剖分-线性变换线段树)

树链剖分若不会的话可自行学习一下. 前两种操作是线性变换,模\(2^{64}\)可将线段树全部用unsigned long long 保存,另其自然溢出. 而取反操作比较不能直接处理,因为其模\(2^{64}\)的特殊性,可将其转化为线性变换. 显然 \[-x\equiv (2^{64}-1)*x (mod\ 2^{64})\] 因为\[!x = (2^{64}-1) -x \] 所以 \[ !x = (2^{64}-1) + (2^{64}-1)x\] #include<bits/stdc++

Luogu2542 AHOI2005 航线规划 树链剖分、线段树

传送门 看到删边不用想就是反着加边 先把删完边之后的图拆一个生成树出来,然后考虑非树边的影响.实际上非树边就是让树上的一条路径的权值从$1$变为了$0$,而每一个询问就是一条路径上的权值之和.使用树链剖分+线段树维护权值即可. 1 #include<bits/stdc++.h> 2 #define lch (now << 1) 3 #define rch (now << 1 | 1) 4 #define mid ((l + r) >> 1) 5 //This