1. 程式人生 > >情報傳遞(message)

情報傳遞(message)

情報傳遞(message)

題目描述

 

奈特公司是一個巨大的情報公司,它有著龐大的情報網路,情報網路中共有n名情報員。每名情報員可能有若干名(可能沒有)下線,除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,表示蒐集情報的情報員編號。


solution

首先把詢問離線。

可以發現如果一個有威脅的人應該在T-c[i]時刻之前就開始收集

按時間為下標,每個點建主席樹。

第k棵樹的每個值表示時間i,k到根的路徑上是否有點出現

由於離線,我們就一開始全部建完。

效率O(nlogn)

xjq神犇用樹狀陣列切掉

把詢問按T-c排序,用樹剖序作下標建樹狀陣列

按時間把點和詢問加入

常數賊小orz

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 200005
using namespace std;
int n,Q,f[maxn][22],head[maxn],t1,t2,tot,deep[maxn];
int ti[maxn],root[maxn],cnt;
struct node{
    int v,nex;
}e[maxn*2];
struct Que{
    int op,x,y,c;
}q[maxn];
struct Node{
    int x,ls,rs;
}tree[maxn*20];
void lj(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void wh(int k){
    tree[k].x=tree[tree[k].ls].x+tree[tree[k].rs].x;
}
void build(int &k,int la,int l,int r,int pl){
    if(!k)k=++cnt;
    if(l==r){tree[k].x=tree[la].x+1;return;}
    int mid=l+r>>1;
    if(pl<=mid)tree[k].rs=tree[la].rs,build(tree[k].ls,tree[la].ls,l,mid,pl);
    else tree[k].ls=tree[la].ls,build(tree[k].rs,tree[la].rs,mid+1,r,pl);
    wh(k);
}
void dfs(int k){
    int fa=f[k][0];deep[k]=deep[fa]+1;
    if(ti[k])build(root[k],root[fa],1,Q,ti[k]);
    else root[k]=root[fa];
    for(int i=head[k];i;i=e[i].nex){
        if(e[i].v!=fa)dfs(e[i].v);  
    }
}
int L(int x,int y){
    if(deep[x]<deep[y])swap(x,y);
    for(int i=20;i>=0;i--)if(deep[f[x][i]]>=deep[y])x=f[x][i];
    for(int i=20;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
    if(x==y)return x;
    return f[x][0];
}
int ask(int t1,int t2,int t3,int t4,int l,int r,int pl){
    if(pl<=0)return 0;
    if(l==r)return tree[t1].x+tree[t2].x-tree[t3].x-tree[t4].x;
    int mid=l+r>>1;
    int s1=tree[t1].ls,s2=tree[t2].ls,s3=tree[t3].ls,s4=tree[t4].ls;
    if(mid<pl){
        int tmp=tree[s1].x+tree[s2].x-tree[s3].x-tree[s4].x;
        s1=tree[t1].rs,s2=tree[t2].rs,s3=tree[t3].rs,s4=tree[t4].rs;
        return tmp+ask(s1,s2,s3,s4,mid+1,r,pl);
    }
    else return ask(s1,s2,s3,s4,l,mid,pl);
}
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%d",&f[i][0]);
        lj(f[i][0],i);
    }
    for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
    cin>>Q;
    for(int i=1;i<=Q;i++){
        scanf("%d",&q[i].op);
        if(q[i].op==1)scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].c);
        else {
            scanf("%d",&q[i].c);
            if(!ti[q[i].c])ti[q[i].c]=i;
        }
    }
    dfs(1);
    for(int i=1;i<=Q;i++){
    if(q[i].op==2)continue;
    int lca=L(q[i].x,q[i].y);
    printf("%d ",deep[q[i].x]+deep[q[i].y]-deep[lca]-deep[f[lca][0]]);
    printf("%d\n",ask(root[q[i].x],root[q[i].y],root[lca],root[f[lca][0]],1,Q,i-q[i].c-1));
    }
    return 0;
}