码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ4196 [NOI2015] 软件包管理器

时间:2016-01-15 22:42:35      阅读:331      评论:0      收藏:0      [点我收藏+]

标签:

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4196http://uoj.ac/problem/128

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步操作中改变安装状态的软件包数。
 

听说这是NOI题目?水水的树链剖分

建立一棵有向树,边由被依赖的软件包指向依赖的软件包

安装一个软件包就从根到这个点的一条链全部改为1,卸载一个软件包就把它的子树全部改为0

根据DFS序的性质,如果一个点在线段树上的编号为 pos[x],子树的最后一个节点的编号就为 pos[x] + size[x] - 1,在线段树上这棵子树是连续的一个区间

软件包的编号从0开始,所以对所有的点都加了一个偏移量1

第一次交的时候打成了 pos[x + size[x] - 1],导致了RE,还有其他的一些bug,出现后从UOJ上找来样例数据

BZOJ的数据太夸张了,UOJ才3317ms

技术分享

技术分享
  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <cstring>
  5 #define rep(i,l,r) for(int i=l; i<=r; i++)
  6 #define clr(x,y) memset(x,y,sizeof(x))
  7 #define travel(x) for(Edge *p=last[x]; p; p=p->pre)
  8 using namespace std;
  9 const int INF = 0x3f3f3f3f;
 10 const int maxn = 100010;
 11 inline int read(){
 12     int ans = 0, f = 1;
 13     char c = getchar();
 14     for(; !isdigit(c); c = getchar())
 15     if (c == -) f = -1;
 16     for(; isdigit(c); c = getchar())
 17     ans = ans * 10 + c - 0;
 18     return ans * f;
 19 }
 20 struct Edge{
 21     Edge *pre; int to;
 22 }edge[maxn<<1];
 23 Edge *last[maxn], *pt = edge;
 24 struct Node{
 25     int l,r,v,t;
 26 }t[maxn<<2];
 27 int n,m,x,y,q,segnum=0,dep[maxn],top[maxn],size[maxn],fa[maxn],pos[maxn];
 28 char ch[10];
 29 inline void addedge(int x,int y){
 30     pt->pre = last[x]; pt->to = y; last[x] = pt++;
 31 }
 32 void dfs(int x){
 33     size[x] = 1;
 34     travel(x){
 35         dep[p->to] = dep[x] + 1;
 36         fa[p->to] = x;
 37         dfs(p->to);
 38         size[x] += size[p->to];
 39     }
 40 }
 41 void dfs(int x,int chain){
 42     pos[x] = ++segnum; top[x] = chain;
 43     int k = 0;
 44     travel(x){
 45         if (size[p->to] > size[k]) k = p->to;
 46     }
 47     if (!k) return;
 48     dfs(k,chain);
 49     travel(x){
 50         if (p->to != k) dfs(p->to,p->to);
 51     }
 52 }
 53 void build(int u,int v,int w){
 54     t[w].l = u; t[w].r = v; t[w].v = 0; t[w].t = -1;
 55     if (u == v) return;
 56     int mid = (u + v) >> 1;
 57     build(u,mid,w<<1); build(mid+1,v,w<<1|1);
 58 }
 59 inline void pushdown(int w){
 60     if (t[w].l == t[w].r || t[w].t == -1) return;
 61     t[w<<1].t = t[w<<1|1].t = t[w].t;
 62     t[w<<1].v = (t[w<<1].r - t[w<<1].l + 1) * t[w].t;
 63     t[w<<1|1].v = (t[w<<1|1].r - t[w<<1|1].l + 1) * t[w].t;
 64     t[w].t = -1;
 65 }
 66 inline void maintain(int w){
 67     t[w].v = t[w<<1].v + t[w<<1|1].v;
 68 }
 69 void modify(int u,int v,int w,int x){
 70     pushdown(w);
 71     if (t[w].l == u && t[w].r == v){
 72         t[w].v = x * (v - u + 1);
 73         t[w].t = x; return;
 74     }
 75     int mid = (t[w].l + t[w].r) >> 1;
 76     if (v <= mid) modify(u,v,w<<1,x);
 77     else if (u > mid) modify(u,v,w<<1|1,x);
 78     else{
 79         modify(u,mid,w<<1,x);
 80         modify(mid+1,v,w<<1|1,x);
 81     }
 82     maintain(w);
 83 }
 84 int query(int u,int v,int w){
 85     pushdown(w);
 86     if (t[w].l == u && t[w].r == v) return t[w].v;
 87     int mid = (t[w].l + t[w].r) >> 1;
 88     if (v <= mid) return query(u,v,w<<1);
 89     else if (u > mid) return query(u,v,w<<1|1);
 90     else return query(u,mid,w<<1) + query(mid+1,v,w<<1|1);
 91 }
 92 int install(int x,int y){
 93     int ret = 0;
 94     while (top[x] != top[y]){
 95         if (dep[top[x]] < dep[top[y]]) swap(x,y);
 96         ret += query(pos[top[x]],pos[x],1);
 97         modify(pos[top[x]],pos[x],1,1);
 98         x = fa[top[x]];
 99     }
100     if (dep[x] < dep[y]) swap(x,y);
101     ret += query(pos[y],pos[x],1);
102     modify(pos[y],pos[x],1,1);
103     return ret;
104 }
105 int uninstall(int x){
106     int ret = query(pos[x],pos[x]+size[x]-1,1);
107     modify(pos[x],pos[x]+size[x]-1,1,0);
108     return ret;
109 }
110 int main(){
111     n = read(); clr(last,0);
112     rep(i,1,n-1){
113         x = read();
114         addedge(x+1,i+1);
115     }
116     dep[1] = 0; dfs(1); dfs(1,1); build(1,n,1);
117     q = read();
118     rep(i,1,q){
119         scanf("%s",ch); x = read() + 1;
120         if (ch[0] == i) printf("%d\n",dep[x] + 1 - install(1,x));
121         else printf("%d\n",uninstall(x));
122     }
123     return 0;
124 }
View Code

 

BZOJ4196 [NOI2015] 软件包管理器

标签:

原文地址:http://www.cnblogs.com/jimzeng/p/bzoj4196.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!