bzoj4196[Noi2015]软件包管理器

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 号软件包会卸载所有的软件包。

 

输入样例#2:
10
0 1 2 1 3 0 0 3 2
10
install 0
install 3
uninstall 2
install 7
install 5
install 9
uninstall 9
install 4
install 1
install 9
输出样例#2:
1
3
2
1
3
1
1
1
0
1


【数据范围】

 

【时限1s,内存512M】

 
 
题解
裸的树链剖分,曾经写过dfs的,新学一种只要bfs的树链剖分,不怕栈溢出。
 
 
代码
  1 program rrr(input,output);
  2 type
  3   etype=record
  4      t,next:longint;
  5    end;
  6    treetype=record
  7      l,r,s,d:longint;
  8    end;
  9 var
 10   e:array[0..200020]of etype;
 11   head,father,dep,top,siz,son,sson,oot,idx,q:array[-3..100010]of longint;
 12   a:array[0..400040]of treetype;
 13   n,qq,i,j,cnt,ans,h,t,x:longint;
 14   s:string;
 15 procedure add(x,y:longint);
 16 begin
 17    inc(cnt);e[cnt].t:=y;e[cnt].next:=head[x];head[x]:=cnt;
 18 end;
 19 procedure prepare;
 20 begin
 21    h:=0;t:=1;q[1]:=0;dep[0]:=1;
 22    while h<t do
 23       begin
 24          inc(h);
 25          i:=head[q[h]];
 26          while i<>0 do
 27             begin
 28                dep[e[i].t]:=dep[q[h]]+1;
 29                inc(t);q[t]:=e[i].t;
 30                i:=e[i].next;
 31             end;
 32       end;
 33    for i:=0 to n-1 do siz[i]:=1;
 34    fillchar(sson,sizeof(sson),0);
 35    for i:=0 to n-1 do son[i]:=-1;
 36    for i:=n downto 2 do
 37       begin
 38          inc(siz[father[q[i]]],siz[q[i]]);
 39          if siz[q[i]]>sson[father[q[i]]] then begin son[father[q[i]]]:=q[i];sson[father[q[i]]]:=siz[q[i]]; end;
 40       end;
 41    fillchar(idx,sizeof(idx),0);father[0]:=-1;oot[-1]:=0;
 42    for i:=1 to n do
 43       if idx[q[i]]=0 then
 44          begin
 45             cnt:=oot[father[q[i]]];j:=q[i];
 46             while j<>-1 do
 47                begin
 48                   top[j]:=q[i];
 49                   inc(cnt);idx[j]:=cnt;oot[j]:=cnt;
 50                   inc(oot[father[j]],siz[j]);
 51                   j:=son[j];
 52                end;
 53          end;
 54 end;
 55 procedure build(k,l,r:longint);
 56 var
 57   mid:longint;
 58 begin
 59    a[k].l:=l;a[k].r:=r;a[k].d:=-1;a[k].s:=0;
 60    if l=r then exit;
 61    mid:=(l+r)>>1;
 62    build(k+k,l,mid);
 63    build(k+k+1,mid+1,r);
 64 end;
 65 procedure pushdown(k:longint);
 66 var
 67   i:longint;
 68 begin
 69    if a[k].l=a[k].r then begin a[k].d:=-1;exit; end;
 70    i:=k+k;
 71    if a[k].d=0 then begin a[i].s:=0;a[i].d:=0;a[i+1].s:=0;a[i+1].d:=0; end
 72    else begin a[i].s:=a[i].r-a[i].l+1;a[i].d:=1;a[i+1].s:=a[i+1].r-a[i+1].l+1;a[i+1].d:=1; end;
 73    a[k].d:=-1;
 74 end;
 75 function ask(k,x,y:longint):longint;
 76 var
 77   mid,ans:longint;
 78 begin
 79    if a[k].d<>-1 then pushdown(k);
 80    if (x<=a[k].l) and (a[k].r<=y) then exit(a[k].s);
 81    ans:=0;mid:=(a[k].l+a[k].r)>>1;
 82    if x<=mid then ans:=ask(k+k,x,y);
 83    if mid<y then ans:=ans+ask(k+k+1,x,y);
 84    exit(ans);
 85 end;
 86 procedure change0(k,x,y:longint);
 87 var
 88   mid,i:longint;
 89 begin
 90    if a[k].d<>-1 then pushdown(k);
 91    if (x<=a[k].l) and (a[k].r<=y) then begin a[k].s:=0;a[k].d:=0;exit;end;
 92    mid:=(a[k].l+a[k].r)>>1;i:=k+k;
 93    if x<=mid then change0(i,x,y);
 94    if mid<y then change0(i+1,x,y);
 95    a[k].s:=a[i].s+a[i+1].s;
 96 end;
 97 procedure change1(k,x,y:longint);
 98 var
 99   mid,i:longint;
100 begin
101    if a[k].d<>-1 then pushdown(k);
102    if (x<=a[k].l) and (a[k].r<=y) then begin a[k].s:=a[k].r-a[k].l+1;a[k].d:=1;exit;end;
103    mid:=(a[k].l+a[k].r)>>1;i:=k+k;
104    if x<=mid then change1(i,x,y);
105    if mid<y then change1(i+1,x,y);
106    a[k].s:=a[i].s+a[i+1].s;
107 end;
108 procedure install;
109 begin
110    ans:=dep[x];
111    while x<>-1 do begin ans:=ans-ask(1,idx[top[x]],idx[x]);change1(1,idx[top[x]],idx[x]);x:=father[top[x]]; end;
112    writeln(ans);
113 end;
114 procedure uninstall;
115 begin
116    writeln(ask(1,idx[x],idx[x]+siz[x]-1));
117    change0(1,idx[x],idx[x]+siz[x]-1);
118 end;
119 begin
120    assign(input,'manager.in');assign(output,'manager.out');reset(input);rewrite(output);
121    readln(n);
122    fillchar(head,sizeof(head),0);cnt:=0;
123    for i:=1 to n-1 do begin read(father[i]);add(father[i],i); end;
124    prepare;
125    build(1,1,n);
126    readln(qq);
127    for i:=1 to qq do
128       begin
129          readln(s);
130          if s[1]='i' then begin delete(s,1,8);val(s,x);install; end
131          else begin delete(s,1,10);val(s,x);uninstall; end;
132       end;
133    close(input);close(output);
134 end.

吐槽:不知道为什么,这个树剖和以前的dfs树剖,在uoj、洛谷、codevs都过了,但在bzoj都过不了,而且上面程序我用cena测了官方数据(dfs的树剖cena测会爆栈),也过了。

posted @ 2017-03-11 16:35  Klaier  阅读(183)  评论(0编辑  收藏  举报