列表

详情


NC20570. [SCOI2015]情报传递

描述

奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有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

说明:

对于3个传递情报任务,都是经过 5名情报员,分别是4号、2号、1号、3号和 7号。

第1个任务,所有情报员 (危险值为 0) 都不对情报构成威胁;第2个任务,有2名情报员对情报构成威胁,分别是1号情报员 (危险值为 3) 和 4号情报员 (危险值为2),7号情报员 (危险值为1) 并不构成威胁;第 3个任务,只有1名情报员对情报构成威胁。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 359ms, 内存消耗: 40584K, 提交时间: 2020-09-28 23:57:23

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N=2e5+10;
int son[N],siz[N],head[N],tot,cnt,id[N],dep[N],top[N],T[N],n,rt,Cnt,fa[N];
struct edge{
    int next,to;
}e[N<<1];
struct Tree{
    int l,r,sum;
}tree[N*50];
int build(int l,int r){
    int id=++tot;tree[id].sum=0;
    if(l==r)return id;
    int mid=l+r>>1;
    tree[id].l=build(l,mid);
    tree[id].r=build(mid+1,r);
    return id;
}
int update(int l,int r,int x,int rt){
    int id=++tot;tree[id]=tree[rt];
    if(l==r){tree[id].sum++;return id;}
    int mid=l+r>>1;
    if(x<=mid)tree[id].l=update(l,mid,x,tree[rt].l);
    else tree[id].r=update(mid+1,r,x,tree[rt].r);
    tree[id].sum=tree[tree[id].l].sum+tree[tree[id].r].sum;
    return id;
}
int query(int l,int r,int L,int R,int rt){
    if(L<=l&&r<=R)return tree[rt].sum;
    int mid=l+r>>1,ans=0;
    if(L<=mid)ans+=query(l,mid,L,R,tree[rt].l);
    if(mid<R)ans+=query(mid+1,r,L,R,tree[rt].r);
    return ans;
}
void add(int u,int v){
    e[++cnt].next=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}
void dfs(int u,int depth){
    siz[u]=1;dep[u]=depth;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;dfs(v,depth+1);
        siz[u]+=siz[v];if(siz[son[u]]<siz[v])son[u]=v;
    }
}
void dfs1(int u,int tp){
    top[u]=tp;id[u]=++Cnt;
    if(son[u])dfs1(son[u],tp);
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].to;if(v==son[u])continue;dfs1(v,v);
    }
}
pii get_sum(int u,int v,int p){
    int tp1=top[u],tp2=top[v];
    int ans=0,res=0;
    while(tp1!=tp2){
        if(dep[tp1]<dep[tp2])swap(tp1,tp2),swap(u,v);
        ans+=query(1,n,id[tp1],id[u],p);res+=id[u]-id[tp1]+1;
        u=fa[tp1];tp1=top[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    ans+=query(1,n,id[u],id[v],p);res+=id[v]-id[u]+1;
    return {res,ans};
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int a;scanf("%d",&a);
        if(a==0)rt=i;
        else add(a,i),fa[i]=a;
    }
    dfs(rt,1);dfs1(rt,rt);
    T[0]=build(1,n);
    int q;scanf("%d",&q);
    for(int i=1;i<=q;i++){
        T[i]=T[i-1];
        int op;scanf("%d",&op);
        if(op==1){
            int x,y,c;scanf("%d %d %d",&x,&y,&c);
            int pre=max(0,i-c-1);
            pii ans=get_sum(x,y,T[pre]);
            printf("%d %d\n",ans.first,ans.second);
        }else {
            int x;scanf("%d",&x);
            T[i]=update(1,n,id[x],T[i]);
        }
    }
}

C++11(clang++ 3.9) 解法, 执行用时: 203ms, 内存消耗: 18392K, 提交时间: 2020-04-01 13:26:03

#include<bits/stdc++.h>
#define rep(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
const int N=202333;
int dep[N],sz[N],size,tot,son[N],top[N],fa[N],begi[N],ed[N],head[N],ans[N][2],c,n,m,x,cnt,t[N];
struct zs{
    int a,b,c,pos,opt;
}a[N];
struct node{
    int next,to;
}e[N<<1];
inline void ins(int u,int v) {
     e[++tot].to=v; e[tot].next=head[u]; head[u]=tot; 
}
inline void dfs1(int x,int pre) {
     dep[x]=dep[fa[x]=pre]+1; sz[x]=1;
     for(int k=head[x];k;k=e[k].next) {
          if(e[k].to==pre)  continue;
          dfs1(e[k].to,x);
          sz[x]+=sz[e[k].to];
          if(sz[e[k].to]>sz[son[x]]) son[x]=e[k].to;
     }
}
void dfs2(int x,int tr) {
     top[x]=tr; 
     if(son[x]) dfs2(son[x],tr);
     for(int k=head[x];k;k=e[k].next) {
          if(e[k].to==fa[x] || e[k].to==son[x]) continue;
          dfs2(e[k].to,e[k].to);
     }
}
inline int lca(int x,int y) {
     int a,b;
     a=top[x]; b=top[y];
     while(a!=b) {
         if(dep[a]<dep[b]) swap(a,b),swap(x,y);
         x=fa[a]; a=top[x];
     }
     if(dep[x]<dep[y]) return x;else return y;
}
void dfs(int x){
    begi[x]=++cnt;
    for(int k=head[x];k;k=e[k].next) dfs(e[k].to);
    ed[x]=cnt;
}
bool cmp(zs a,zs b){
    return a.c==b.c?a.opt<b.opt:a.c<b.c;
}
inline void add(int x,int k){
    while(x<=n) t[x]+=k,x+=x&-x;
}
inline int ask(int x){
    int sum=0;
    while(x) sum+=t[x],x-=x&-x;
    return sum;
}
inline int read(){
    int x=0,c=getchar();
    while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return x;
}
int main(){
    scanf("%d",&n);
    rep(i,1,n) {x=read(); if(x)ins(x,i);}
    dfs(1);
    dfs1(1,0);
    dfs2(1,1);
    scanf("%d",&m);
    rep(i,1,m){
        a[i].opt=read();
        if(a[i].opt==1){
            a[i].a=read(); a[i].b=read(); a[i].c=read();
            a[i].pos=++size;
            a[i].c=i-a[i].c;
        }else a[i].a=read(),a[i].c=i;
    }
    sort(a+1,a+1+m,cmp);
    rep(i,1,m)if(a[i].opt==2){
        add(begi[a[i].a],1); add(ed[a[i].a]+1,-1);
    }else {
        c=lca(a[i].a,a[i].b);
        ans[a[i].pos][0]=dep[a[i].a]+dep[a[i].b]-2*dep[c]+1;
        ans[a[i].pos][1]=ask(begi[a[i].a])+ask(begi[a[i].b])-ask(begi[c])-ask(begi[fa[c]]);
    }
    rep(i,1,size) printf("%d %d\n",ans[i][0],ans[i][1]);
}

上一题