BZOJ_4448_[Scoi2015]情报传递_主席树

Posted fcwww

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ_4448_[Scoi2015]情报传递_主席树相关的知识,希望对你有一定的参考价值。

BZOJ_4448_[Scoi2015]情报传递_主席树

Description

奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有n名情报员。每名情报员口J-能有
若T名(可能没有)下线,除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

 离线,求出每个点开始搜集情报的最早的时间。

然后询问相当于查询有多少个点,满足位置和时间两个条件。

于是用主席树数一下点即可。

主席树维护根到路径的信息。

 

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 200050
int head[N],to[N<<1],nxt[N<<1],cnt,dfn[N],dep[N],fa[N],root[N],ls[N*30],rs[N*30],t[N*30],tot;
int f[N][20],rt,n,m;
struct A {
    int opt,x,y,z;
}a[N];
inline void add(int u,int v) {
    to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;
}
void insert(int &y,int x,int l,int r,int v) {
    y=++tot; t[y]=t[x]+1;
    if(l==r) return ;
    int mid=(l+r)>>1;
    if(v<=mid) rs[y]=rs[x],insert(ls[y],ls[x],l,mid,v);
    else ls[y]=ls[x],insert(rs[y],rs[x],mid+1,r,v);
}
void dfs(int x,int y) {
    int i;
    f[x][0]=y;
    if(dfn[x]) insert(root[x],root[y],1,m,dfn[x]);
    else root[x]=root[y];
    dep[x]=dep[y]+1;
    for(i=head[x];i;i=nxt[i]) {
        if(to[i]!=y) {
            dfs(to[i],x);
        }
    }
}
int lca(int x,int y) {
    int i;
    if(dep[x]<dep[y]) swap(x,y);
    for(i=18;i>=0;i--) {
        if(f[x][i]&&dep[f[x][i]]>=dep[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(i=18;i>=0;i--) {
        if(f[x][i]!=f[y][i]) {
            x=f[x][i]; y=f[y][i];
        } 
    }
    return f[x][0];
}
int query(int x,int y,int z,int w,int l,int r,int v) {
    if(l==r) return t[x]+t[y]-t[z]-t[w];
    int sizls=t[ls[x]]+t[ls[y]]-t[ls[z]]-t[ls[w]],mid=(l+r)>>1;
    if(v<=mid) return query(ls[x],ls[y],ls[z],ls[w],l,mid,v);
    else return query(rs[x],rs[y],rs[z],rs[w],mid+1,r,v)+sizls;
}
int main() {
    scanf("%d",&n);
    int i,x,j;
    for(i=1;i<=n;i++) {
        scanf("%d",&x);
        if(x) {
            add(x,i); add(i,x);
        }
    }
    scanf("%d",&m);
    for(i=1;i<=m;i++) {
        scanf("%d",&a[i].opt);
        if(a[i].opt==1) {
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
        }else {
            scanf("%d",&x); if(!dfn[x]) dfn[x]=i;
        }
    }
    dfs(1,0);
    for(j=1;(1<<j)<=n;j++) {
        for(i=1;i<=n;i++) {
            f[i][j]=f[f[i][j-1]][j-1];
        }
    }
    for(i=1;i<=m;i++) {
        if(a[i].opt==1) {
            int l=lca(a[i].x,a[i].y);
            int p=f[l][0];
            printf("%d ",dep[a[i].x]+dep[a[i].y]-2*dep[l]+1);
            if(i-a[i].z<=0) {
                printf("0\n");continue;
            }
            printf("%d\n",query(root[a[i].x],root[a[i].y],root[l],root[p],1,m,i-a[i].z-1));
        }
    }
}

 

以上是关于BZOJ_4448_[Scoi2015]情报传递_主席树的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 4448: [Scoi2015]情报传递

4448: [Scoi2015]情报传递|主席树|离线操作

BZOJ4448[Scoi2015]情报传递 主席树+LCA

bzoj4448: [Scoi2015]情报传递

BZOJ 4448 情报传递

BZOJ [Scoi2015]情报传递