1. 程式人生 > >BZOJ_P4196 [NOI2015]軟體包管理器(樹鏈剖分+dfs序)

BZOJ_P4196 [NOI2015]軟體包管理器(樹鏈剖分+dfs序)

Linux 使用者和 OS X 使用者一定對軟體包管理器不會陌生。通過軟體包管理器,你可以通過一行命令安裝某一個軟體包,然後軟體包管理器會幫助你從軟體源下載軟體包,同時自動解決所有的依賴(即下載安裝這個軟體包的安裝所依賴的其它軟體包),完成所有的配置。Debian/Ubuntu 使用的 apt-get,Fedora/CentOS 使用的 yum,以及 OS X 下可用的 homebrew 都是優秀的軟體包管理器。

你決定設計你自己的軟體包管理器。不可避免地,你要解決軟體包之間的依賴問題。如果軟體包 AA 依賴軟體包 BB,那麼安裝軟體包 AA 以前,必須先安裝軟體包 BB。同時,如果想要解除安裝軟體包 BB,則必須解除安裝軟體包 AA。現在你已經獲得了所有的軟體包之間的依賴關係。而且,由於你之前的工作,除 00 號軟體包以外,在你的管理器當中的軟體包都會依賴一個且僅一個軟體包,而 00 號軟體包不依賴任何一個軟體包。依賴關係不存在環(若有 mm (m≥2)(m≥2) 個軟體包 A1,A2,A3,…,AmA1,A2,A3,…,Am,其中 A1A1 依賴 A2A2,A2A2 依賴 A3A3,A3A3 依賴 A4A4,……,Am−1Am−1 依賴 AmAm,而 AmAm 依賴 A1A1,則稱這 mm 個軟體包的依賴關係構成環),當然也不會有一個軟體包依賴自己。

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

輸入格式
輸入檔案的第 11 行包含 11 個正整數 nn,表示軟體包的總數。軟體包從 00 開始編號。

隨後一行包含 n−1n−1 個整數,相鄰整數之間用單個空格隔開,分別表示 1,2,3,…,n−2,n−11,2,3,…,n−2,n−1 號軟體包依賴的軟體包的編號。

接下來一行包含 11 個正整數 qq,表示詢問的總數。

之後 qq 行,每行 11 個詢問。詢問分為兩種:

install xx:表示安裝軟體包 xx
uninstall xx:表示解除安裝軟體包 xx
你需要維護每個軟體包的安裝狀態,一開始所有的軟體包都處於未安裝狀態。對於每個操作,你需要輸出這步操作會改變多少個軟體包的安裝狀態,隨後應用這個操作(即改變你維護的安裝狀態)。

輸出格式
輸出檔案包括 qq 行。

輸出檔案的第 ii 行輸出 11 個整數,為第 ii 步操作中改變安裝狀態的軟體包數。

樣例一
input

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

output

3
1
3
2
3

explanation

一開始所有的軟體包都處於未安裝狀態。

安裝 55 號軟體包,需要安裝 0,1,50,1,5 三個軟體包。

之後安裝 66 號軟體包,只需要安裝 66 號軟體包。此時安裝了 0,1,5,60,1,5,6 四個軟體包。

解除安裝 11 號軟體包需要解除安裝 1,5,61,5,6 三個軟體包。此時只有 00 號軟體包還處於安裝狀態。

之後安裝 44 號軟體包,需要安裝 1,41,4 兩個軟體包。此時 0,1,40,1,4 處在安裝狀態。

最後,解除安裝 00 號軟體包會解除安裝所有的軟體包。

樣例二
input

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

output

1
3
2
1
3
1
1
1
0
1

樣例三
見樣例資料下載。

限制與約定
測試點編號 nn 的規模 qq 的規模 備註
1 n=5000n=5000 q=5000q=5000
2
3 n=100000n=100000 q=100000q=100000 資料不包含解除安裝操作
4
5 n=100000n=100000 q=100000q=100000 編號為 ii 的軟體包所依賴的軟體包編號在 [0,i−1][0,i−1] 內均勻隨機。
每次執行操作的軟體包編號在 [0,n−1][0,n−1] 內均勻隨機。
6
7
8
9 n=100000n=100000 q=100000q=100000
10
11
12
13
14
15
16
17
18
19
20
時間限制:1s1s
空間限制:512MB

Sol:
NOI水題…

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;
#define N 500005
#define mid ((l+r)>>1)
int n,m,cnt;vector<int> g[N];
int sz[N],top[N],p[N],f[N],son[N],dep[N],dfsn[N];
struct SegTree{
    int d[N*4],g[N*4],lg[N*4];
    void Updata(int o){d[o]=d[o<<1]+d[o<<1|1];}
    void Push(int o){
        if(~g[o]){
            if(g[o]) d[o<<1]=lg[o<<1],d[o<<1|1]=lg[o<<1|1];
            else d[o<<1]=d[o<<1|1]=0;
            g[o<<1]=g[o<<1|1]=g[o],g[o]=-1;
        }
    }
    void Build(int o,int l,int r){
        if(l==r){d[o]=0,g[o]=-1,lg[o]=1;return;}
        Build(o<<1,l,mid);Build(o<<1|1,mid+1,r);
        lg[o]=lg[o<<1]+lg[o<<1|1],g[o]=-1;
    }
    int Query0(int o,int l,int r,int ql,int qr,int res=0){
        if(ql<=l&&r<=qr) return lg[o]-d[o];
        Push(o);
        if(ql<=mid) res+=Query0(o<<1,l,mid,ql,qr);
        if(qr>mid) res+=Query0(o<<1|1,mid+1,r,ql,qr);
        return res;
    }
    int Query1(int o,int l,int r,int ql,int qr,int res=0){
        if(ql<=l&&r<=qr) return d[o];
        Push(o);
        if(ql<=mid) res+=Query1(o<<1,l,mid,ql,qr);
        if(qr>mid) res+=Query1(o<<1|1,mid+1,r,ql,qr);
        return res;
    }
    void Change(int o,int l,int r,int ql,int qr,int v){
        if(ql<=l&&r<=qr){g[o]=v,d[o]=lg[o]*v;return;}
        Push(o);
        if(ql<=mid) Change(o<<1,l,mid,ql,qr,v);
        if(qr>mid) Change(o<<1|1,mid+1,r,ql,qr,v);
        Updata(o);
    }
    int GetAns(int u,int v,int res=0){
        int f1=top[u],f2=top[v];
        while(f1!=f2){
            if(dep[f1]<dep[f2]) swap(u,v),swap(f1,f2);
            res+=Query0(1,1,n,p[f1],p[u]);Change(1,1,n,p[f1],p[u],1);
            u=f[f1],f1=top[u];
        }
        if(dep[u]>dep[v]) swap(u,v);
        res+=Query0(1,1,n,p[u],p[v]);Change(1,1,n,p[u],p[v],1);
        return res;
    }
}seg;
void dfs1(int u,int fa,int d){
    f[u]=fa,sz[u]=1,dep[u]=d;
    for(int i=0,v,lim=g[u].size();i<lim;i++)
        if((v=g[u][i])!=fa){
            dfs1(v,u,d+1),sz[u]+=sz[v];
            if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
        }
}
void dfs2(int u,int tp){
    p[u]=++cnt,top[u]=tp;
    if(!son[u]){dfsn[u]=cnt;return;}dfs2(son[u],tp);
    for(int i=0,v,lim=g[u].size();i<lim;i++){
        if((v=g[u][i])!=f[u]&&v!=son[u]) dfs2(v,v);
    }dfsn[u]=cnt;
}
inline int in(int x=0,char ch=getchar()){while(ch>'9'||ch<'0') ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();return x;}
char str[65];
void print(long long x){
    int l=0;if(!x){putchar('0');return;}if(x<0) putchar('-'),x=-x;
    while(x) str[++l]=x%10+'0',x/=10;while(l) putchar(str[l--]);}
int main(){
    n=in();
    for(int i=2,x;i<=n;i++) x=in()+1,g[x].push_back(i);
    dfs1(1,1,1);dfs2(1,1);seg.Build(1,1,n);
    m=in();char opt[15];
    while(m--){
        scanf("%s",opt);
        if(opt[0]=='i'){
            print(seg.GetAns(1,in()+1)),putchar('\n');
        }else{
            int x=in()+1;
            print(seg.Query1(1,1,n,p[x],dfsn[x])),putchar('\n'),
                seg.Change(1,1,n,p[x],dfsn[x],0);
        }
    }
    return 0;
}