奈特公司是一個巨大的情報公司,它有着龐大的情報網絡,情報網絡中共有n名情報員。每名情報員可能有若干名(可能沒有)下線,除1名大頭目外其他n-1名情報員有且僅有1名上線。奈特公司紀律森嚴,每名情報員只能與本身的上、下線聯繫,同時,情報網絡中任意兩名情報員必定可以經過情報網絡傳遞情報。node
奈特公司天天會派發如下兩種任務中的一個任務:ios
一、蒐集情報:指派T號情報員蒐集情報數組
二、傳遞情報:將一條情報從X號情報員傳遞至Y號情報員安全
情報員最初處於潛伏階段,他們是相對安全的,咱們認爲此時全部情報員的危險值爲0;一旦某個情報員開始蒐集情報,他的危險值就會持續增長,天天增長1點危險值(開始蒐集情報的當天危險值仍爲0,第2天危險值爲1,第3天危險值爲2,以此類推)。傳遞情報並不會使情報員的危險值增長。網絡
爲了保證傳遞情報的過程相對安全,每條情報都有一個風險控制值C。奈特公司認爲,參與傳遞這條情報的全部情報員中,危險值大於C的情報員將對這條情報構成威脅。如今,奈特公司但願知道,對於每一個傳遞情報任務,參與傳遞的情報員有多少個,其中對這條情報構成威脅的情報員有多少個。ui
第1行包含1個正整數n,表示情報員個數。spa
第2行包含n個非負整數,其中第i個整數Pi表示i號情報員上線的編號。特別地,若Pi=0,表示i號情報員是大頭目。code
第3行包含1個正整數q,表示奈特公司將派發q個任務(天天一個)。排序
隨後q行,依次描述q個任務。ci
每行首先有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; }