1. 程式人生 > >BZOJ4196:[NOI2015]軟件包管理器——題解

BZOJ4196:[NOI2015]軟件包管理器——題解

bzoj pushd 註意 軟件 com AR 依賴 ini cstring

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

https://www.luogu.org/problemnew/show/P2146

你決定設計你自己的軟件包管理器。不可避免地,你要解決軟件包之間的依賴問題。如果軟件包A依賴軟件包B,那麽安裝軟件包A以前,必須先安裝軟件包B。同時,如果想要卸載軟件包B,則必須卸載軟件包A。現在你已經獲得了所有的軟件包之間的依賴關系。而且,由於你之前的工作,除0號軟件包以外,在你的管理器當中的軟件包都會依賴一個且僅一個軟件包,而0號軟件包不依賴任何一個軟件包。依賴關系不存在環(若有m(m≥2)個軟件包A1,A2,A3,?,Am,其中A1依賴A2,A2依賴A3,A3依賴A4,……,A[m-1]依賴Am,而Am依賴A1,則稱這m個軟件包的依賴關系構成環),當然也不會有一個軟件包依賴自己。

現在你要為你的軟件包管理器寫一個依賴解決程序。根據反饋,用戶希望在安裝和卸載某個軟件包時,快速地知道這個操作實際上會改變多少個軟件包的安裝狀態(即安裝操作會安裝多少個未安裝的軟件包,或卸載操作會卸載多少個已安裝的軟件包),你的任務就是實現這個部分。註意,安裝一個已安裝的軟件包,或卸載一個未安裝的軟件包,都不會改變任何軟件包的安裝狀態,即在此情況下,改變安裝狀態的軟件包數為0。

題面很長,耐心看完就知道這是道樹剖的板子題。

(然而不會求子樹和的我還是去看了題解)

我們把安裝的權值為1,未安裝為0。

對於下載操作只需要查詢該點到根節點的路程-1的個數。

對於卸載操作只需要查詢該點的子樹的1的個數。

(當然別忘了二者的修改。)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=2e5+5;
const int INF=2147483647;
inline int read(){
    int X=0,w=0;char ch=0;
    while(ch<0||ch>9){w|=ch==-
;ch=getchar();} while(ch>=0&&ch<=9)X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int to,nxt; }edge[2*N]; struct tree{ int lazy,sum; }t[4*N]; int head[N],cnt,tot,n; inline void add(int u,int v){ edge[++cnt].to=v;edge[cnt].nxt=head[u];head[u]=cnt; } int fa[N],dep[N],size[N],son[N],top[N],pos[N],idx[N]; void dfs1(int u){ size[u]=1; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(!son[u]||size[v]>size[son[u]])son[u]=v; } return; } void dfs2(int u,int anc){ tot++; pos[u]=tot; idx[tot]=u; top[u]=anc; if(!son[u])return; dfs2(son[u],anc); for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v==fa[u]||v==son[u])continue; dfs2(v,v); } return; } inline void pushdown(int a,int l,int r){ int mid=(l+r)>>1; if(t[a].lazy!=-1){ t[a*2].lazy=t[a*2+1].lazy=t[a].lazy; t[a*2].sum=t[a].lazy*(mid-l+1); t[a*2+1].sum=t[a].lazy*(r-mid); t[a].lazy=-1; } return; } void modify(int a,int l,int r,int l1,int r1,int v){ if(r1<l||r<l1)return; if(l1<=l&&r<=r1){ t[a].sum=v*(r-l+1); t[a].lazy=v; return; } int mid=(l+r)>>1; pushdown(a,l,r); modify(a*2,l,mid,l1,r1,v); modify(a*2+1,mid+1,r,l1,r1,v); t[a].sum=t[a*2].sum+t[a*2+1].sum; return; } void pathmodify(int u,int v,int c){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;} modify(1,1,n,pos[top[u]],pos[u],c); u=fa[top[u]]; } if(dep[u]>dep[v]){int t=u;u=v;v=t;} modify(1,1,n,pos[u],pos[v],c); return; } inline void nodemodify(int u,int c){ modify(1,1,n,pos[u],pos[u]+size[u]-1,c); } int query(int a,int l,int r,int l1,int r1){//線段樹區間和 if(r1<l||l1>r)return 0; if(l1<=l&&r<=r1)return t[a].sum; int mid=(l+r)>>1; pushdown(a,l,r); return query(a*2,l,mid,l1,r1)+query(a*2+1,mid+1,r,l1,r1); } int pathquery(int u,int v){//詢問(u,v)這條路徑的和 if(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;} return pos[u]-pos[top[u]]+1 +pathquery(fa[top[u]],v)-query(1,1,n,pos[top[u]],pos[u]); } if(dep[u]>dep[v]){int t=u;u=v;v=t;} return pos[v]-pos[u]+1-query(1,1,n,pos[u],pos[v]); } inline int nodequery(int u){ return query(1,1,n,pos[u],pos[u]+size[u]-1); } void init(){ dep[1]=fa[1]=1; dfs1(1); top[1]=idx[1]=pos[1]=1; tot=0; dfs2(1,1); for(int i=1;i<4*n;i++)t[i].lazy=-1; return; } int main(){ n=read(); for(int i=2;i<=n;i++){ int v=read()+1; add(i,v);add(v,i); } init(); int q=read(); while(q--){ char op[20]; scanf("%s",op); int u=read()+1; if(op[0]==i){ printf("%d\n",pathquery(u,1)); pathmodify(u,1,1); } else{ printf("%d\n",nodequery(u)); nodemodify(u,0); } } return 0; }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+歡迎訪問我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4196:[NOI2015]軟件包管理器——題解