1. 程式人生 > >【BZOJ4448】[Scoi2015]情報傳遞 主席樹+LCA

【BZOJ4448】[Scoi2015]情報傳遞 主席樹+LCA

std [0 參與 tput rip 正整數 控制 i++ getchar()

【BZOJ4448】[Scoi2015]情報傳遞

Description

奈特公司是一個巨大的情報公司,它有著龐大的情報網絡。情報網絡中共有n名情報員。每名情報員能有若幹名(可能沒有)下線,除1名大頭日外其余n-1名情報員有且僅有1名上線。奈特公司紀律森嚴,每名情報員只能與自己的上、下線聯系,同時,情報網絡中仟意兩名情報員一定能夠通過情報網絡傳遞情報。 奈特公司每天會派發以下兩種任務中的一個任務: 1.搜集情報:指派T號情報員搜集情報 2.傳遞情報:將一條情報從X號情報員傳遞給Y號情報員 情報員最初處於潛伏階段,他們是相對安全的,我們認為此時所有情報員的危險值為0;-旦某個情報員開始搜集情報,他的危險值就會持續增加,每天增加1點危險值(開始搜集情報的當天危險值仍為0,第2天危險值為1,第3天危險值為2,以此類推)。傳遞情報並不會使情報員的危險值增加。為了保證傳遞情報的過程相對安全,每條情報都有一個風險控制值C。余特公司認為,參與傳遞這條情報的所有情報員中,危險值大於C的情報員將對該條情報構成威脅。現在,奈特公司希望知道,對於每個傳遞情報任務,參與傳遞的情報員有多少個,其中對該條情報構成威脅的情報員有多少個。

Input

第1行包含1個正整數n,表示情報員個數。 笫2行包含n個非負整數,其中第i個整數Pi表示i號情報員上線的編號。特別地,若Pi=0,表示i號情報員是大頭目。 第3行包含1個正整數q,表示奈特公司將派發q個任務(每天一個)。 隨後q行,依次描述q個任務。每行首先有1個正整數k。若k=1,表示任務是傳遞情報,隨後有3個正整數Xi、Yi、Ci,依次表示傳遞情報的起點、終點和風險控制值;若k=2,表示任務是搜集情報,隨後有1個正整數Ti,表示搜集情報的情報員編號。

Output

對於每個傳遞情報任務輸出一行,應包含兩個整數,分別是參與傳遞情報的情報員個數和對該條情報構成威脅的情報員個數。輸出的行數應等於傳遞情報任務的個數,每行僅包含兩個整數,用一個空格隔開。輸出不應包含多余的空行和空格。

Sample Input

7
0 1 1 2 2 3 3
6
1 4 7 0
2 1
2 4
2
7
1 4 7 1
1 4 7 3

Sample Output

5 0 5 2 5 1

HINT

對於3個傳遞情報任務,都是經過5名情報員,分別是4號、2號、1號、3號和7號。其中,對於第1個任務,所有情報員(危險值為0)都不對情報構成威脅;對於第2個任務,有2名情報員對情報構成威脅,分別是1號情報員(危險值為3)和4號情報員(危險值為2),7號情報員(危險值為1)並不構成威脅;對於第3個任務,只有1名情報員對情報構成威脅。 n< = 2×10^5,Q< = 2×105,0< Pi,C!< = N, 1< = Ti,Xi,Yi< = n

題解

:離線處理+主席樹+倍增LCA,沒有別的了~

#include <cstdio> 
#include <cstring> 
#include <iostream> 
using namespace std; 
const int maxn=200010; 
struct sag 
{ 
    int ls,rs,siz; 
}s[maxn*30]; 
int n,m,cnt,root,tot; 
int rt[maxn],fa[maxn][20],to[maxn],next[maxn],head[maxn],dep[maxn]; 
int v[maxn],qa[maxn],qb[maxn],qc[maxn]; 
int rd() 
{ 
    int ret=0;  char gc=getchar(); 
    while(gc<‘0‘||gc>‘9‘) gc=getchar(); 
    while(gc>=‘0‘&&gc<=‘9‘)   ret=ret*10+gc-‘0‘,gc=getchar(); 
    return ret; 
} 
void add(int a,int b) 
{ 
    to[cnt]=b,next[cnt]=head[a],head[a]=cnt++; 
} 
void insert(int x,int &y,int l,int r,int pos) 
{ 
    if(!pos) 
    { 
        y=x; 
        return ; 
    } 
    y=++tot; 
    if(l==r) 
    { 
        s[y].siz++; 
        return; 
    } 
    int mid=l+r>>1; 
    if(pos<=mid) s[y].rs=s[x].rs,insert(s[x].ls,s[y].ls,l,mid,pos); 
    else    s[y].ls=s[x].ls,insert(s[x].rs,s[y].rs,mid+1,r,pos); 
    s[y].siz=s[x].siz+1; 
} 
void dfs(int x) 
{ 
    insert(rt[fa[x][0]],rt[x],1,m,v[x]); 
    for(int i=head[x];i!=-1;i=next[i])  dep[to[i]]=dep[x]+1,dfs(to[i]); 
} 
int query(int a,int b,int c,int d,int l,int r,int pos) 
{ 
    if(pos<=0)   return 0; 
    if(r<=pos)   return s[a].siz+s[b].siz-s[c].siz-s[d].siz; 
    int mid=l+r>>1; 
    if(pos<=mid) return query(s[a].ls,s[b].ls,s[c].ls,s[d].ls,l,mid,pos); 
    return s[s[a].ls].siz+s[s[b].ls].siz-s[s[c].ls].siz-s[s[d].ls].siz+query(s[a].rs,s[b].rs,s[c].rs,s[d].rs,mid+1,r,pos); 
} 
int main() 
{ 
    n=rd(); 
    int i,j,a,b,c; 
    memset(head,-1,sizeof(head)); 
    for(i=1;i<=n;i++) 
    { 
        fa[i][0]=rd(); 
        if(!fa[i][0])   root=i; 
        else    add(fa[i][0],i); 
    } 
    m=rd(); 
    for(i=1;i<=m;i++) 
    { 
        b=rd(); 
        if(b==1)    qa[i]=rd(),qb[i]=rd(),qc[i]=i-rd()-1; 
        else    a=rd(),v[a]=i; 
    } 
    for(j=1;(1<<j)<n;j++) 
        for(i=1;i<=n;i++) 
            fa[i][j]=fa[fa[i][j-1]][j-1]; 
    dep[1]=1,dfs(1); 
    for(i=1;i<=m;i++) 
    { 
        if(qa[i]) 
        { 
            a=qa[i],b=qb[i]; 
            if(dep[a]<dep[b])    swap(a,b); 
            for(j=19;j>=0;j--)   if(dep[fa[a][j]]>=dep[b])    a=fa[a][j]; 
            if(a!=b) 
            { 
                for(j=19;j>=0;j--)   if(fa[a][j]!=fa[b][j])  a=fa[a][j],b=fa[b][j]; 
                a=fa[a][0]; 
            } 
            c=dep[qa[i]]+dep[qb[i]]-2*dep[a]+1; 
            printf("%d %d\n",c,query(rt[qa[i]],rt[qb[i]],rt[a],rt[fa[a][0]],1,m,qc[i])); 
        } 
    } 
    return 0; 
}

【BZOJ4448】[Scoi2015]情報傳遞 主席樹+LCA