鏈接:https://ac.nowcoder.com/acm/problem/20570
來源:牛客網
時間限制:C/C++ 2秒,其他語言4秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld
題目描述
奈特公司是一個巨大的情報公司,它有着龐大的情報網絡。情報網絡中共有n名情報員。每名情報員口J-能有若T名(可能沒有)下線,除1名大頭日外其餘n-1名情報員有且僅有1名上線。奈特公司紀律森嚴,每名情報員只能與自己的上、下線聯繫,同時,情報網絡中仟意兩名情報員一定能夠通過情報網絡傳遞情報。
奈特公司每天會派發以下兩種任務中的一個任務:
1.蒐集情報:指派T號情報員蒐集情報
2.傳遞情報:將一條情報從X號情報員傳遞給Y號情報員
情報員最初處於潛伏階段,他們是相對安全的,我們認爲此時所有情報員的危險值爲0;
一旦某個情報員開始蒐集情報,他的危險值就會持續增加,每天增加1點危險值(開始蒐集情報的當天危險值仍爲0,第2天危險值爲1,第3天危險值爲2,以此類推)。
傳遞情報並不會使情報員的危險值增加。 爲了保證傳遞情報的過程相對安全,每條情報都有一個風險控制值C。餘特公司認爲,參與傳遞這條情報的所有情報員中,危險值大於C的情報員將對該條情報構成威脅。現在,奈特公司希望知道,對於每個傳遞情報任務,參與傳遞的情報員有多少個,其中對該條情報構成威脅的情報員有多少個。
輸入描述:
第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,表示蒐集情報的情報員編號。
輸出描述:
對於每個傳遞情報任務輸出一行,應包含兩個整數,分別是參與傳遞情報的情報員個數和對該條情報構成威脅的情報員個數。 輸出的行數應等於傳遞情報任務的個數,每行僅包含兩個整數,用一個空格隔開。輸出不應包含多餘的空行和空格。
示例1
輸入
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
輸出
5 0 5 2 5 1
ps:挺簡單的主席樹,就先預處理出詢問,然後按照詢問建樹,對於沒蒐集信息的點初始值定位比總位數還大,這樣不管怎麼詢問都不會詢問到,然後就是個求lca的問題了,看代碼就明白了
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+5000;
const int mm=2e5+2;
int tot;
int n;
struct rt{
int v,next;
}edge[maxn];
struct ry{
int x,y,c,id;
}Q[maxn];
int head[maxn],val[maxn];
int dep[maxn],rt[maxn],sum[maxn*100],lson[maxn*100],rson[maxn*100];
int cnt;
int f[maxn][50];
void add_edge(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
}
void update(int pre,int &now,int l,int r,int L){
sum[now=++cnt]=sum[pre]+1;
lson[now]=lson[pre],rson[now]=rson[pre];
if(l==r)return;
int mid=(l+r)>>1;
if(L<=mid)update(lson[pre],lson[now],l,mid,L);
else update(rson[pre],rson[now],mid+1,r,L);
}
void dfs(int u,int fa){
dep[u]=dep[fa]+1;
f[u][0]=fa;
update(rt[fa],rt[u],1,mm,val[u]);
for(int i=head[u];~i;i=edge[i].next){
int v=edge[i].v;
dfs(v,u);
}
}
void getLca(){
for(int i=1;i<=19;i++){
for(int j=1;j<=n;j++){
f[j][i]=f[f[j][i-1]][i-1];
}
}
}
int findLca(int u,int v){
for(int i=19;i>=0;i--){
if(dep[f[u][i]]<dep[v])continue;
u=f[u][i];
}
if(u==v)return u;
for(int i=19;i>=0;i--){
if(f[u][i]!=f[v][i]){
u=f[u][i];v=f[v][i];
}
}
return f[u][0];
}
int query(int u,int preu,int v,int prev,int l,int r,int L){
if(r<=L){
return sum[u]-sum[preu]+sum[v]-sum[prev];
}
int mid=(l+r)>>1;
if(L<=mid)return query(lson[u],lson[preu],lson[v],lson[prev],l,mid,L);
else return sum[lson[u]]-sum[lson[preu]]+sum[lson[v]]-sum[lson[prev]]+
query(rson[u],rson[preu],rson[v],rson[prev],mid+1,r,L);
}
void solve(int u,int v,int c,int k){
if(dep[u]<dep[v])swap(u,v);
int lca=findLca(u,v);
int num=sum[rt[u]]-sum[rt[f[lca][0]]]+sum[rt[v]]-sum[rt[lca]];
printf("%d ",num);
if(k-c<=1)printf("%d\n",0);
else{
printf("%d\n",query(rt[u],rt[f[lca][0]],rt[v],rt[lca],1,mm,k-c-1));
}
}
int main(){
memset(head,-1,sizeof(head));
int s;
scanf("%d",&n);
int u;
for(int i=1;i<=n;i++){
scanf("%d",&u);
if(u==0)s=i;
else add_edge(u,i);
}
for(int i=1;i<=n;i++)val[i]=mm;
int m;scanf("%d",&m);
int tt=0;
for(int i=1;i<=m;i++){
scanf("%d",&u);
if(u==1){
scanf("%d%d%d",&Q[tt].x,&Q[tt].y,&Q[tt].c);
Q[tt++].id=i;
}
else{
int v;scanf("%d",&v);
val[v]=i;
}
}
dfs(s,0);
getLca();
for(int i=0;i<tt;i++){
solve(Q[i].x,Q[i].y,Q[i].c,Q[i].id);
}
return 0;
}