DTOJ2351 情报传递(message)

58 篇文章 0 订阅

题目

题目描述

奈特公司是一个巨大的情报公司,它有着庞大的情报网络,情报网络中共有 n n n名情报员
每名情报员可能有若干名(可能没有)下线,除 1 1 1名大头目外其余 n − 1 n-1 n1名情报员有且仅有 1 1 1名上线
奈特公司纪律森严,每名情报员只能与自己的上、下线联系(???),同时,情报网络中任意两名情报员一定能够通过情报网络传递情报
奈特公司每天会派发以下两种任务中的一个任务:

  1. 搜集情报:指派T号情报员搜集情报
  2. 传递情报:将一条情报从X号情报员传递至Y号情报员

情报员最初处于潜伏阶段,他们是相对安全的,我们认为此时所有情报员的危险值为 0 0 0
一旦某个情报员开始搜集情报,他的危险值就会持续增加,每天增加 1 1 1点危险值(开始搜集情报的当天危险值仍为 0 0 0,第 2 2 2天危险值为 1 1 1,第 3 3 3天危险值为 2 2 2,以此类推)
传递情报并不会使情报员的危险值增加
为了保证传递情报的过程相对安全,每条情报都有一个风险控制值 C C C
奈特公司认为,参与传递这条情报的所有情报员中,危险值大于 C C C的情报员将对这条情报构成威胁
现在,奈特公司希望知道,对于每个传递情报任务,参与传递的情报员有多少个,其中对这条情报构成威胁的情报员有多少个

输入格式

1 1 1行包含 1 1 1个正整数 n n n,表示情报员个数
2 2 2行包含 n n n个非负整数,其中第 i i i个整数 P i P_i Pi表示 i i i号情报员上线的编号
特别地,若 P i = 0 P_i=0 Pi=0,表示i号情报员是大头目
3 3 3行包含 1 1 1个正整数 q q q,表示奈特公司将派发 q q q个任务(每天一个)
随后 q q q行,依次描述 q q q个任务
每行首先有 1 1 1个正整数 k k k
k = 1 k=1 k=1,表示任务是传递情报,随后有 3 3 3个正整数 X i 、 Y i 、 C i X_i、Y_i、C_i XiYiCi,依次表示传递情报的起点、终点和风险控制值
k = 2 k=2 k=2,表示任务是搜集情报,随后有 1 1 1个正整数 T i T_i Ti,表示搜集情报的情报员编号

输出格式

对于每个传递情报任务输出一行,应包含两个整数,分别是参与传递情报的情报员个数和对该条情报构成威胁的情报员个数
输出的行数应等于传递情报任务的个数,每行仅包含两个整数,用一个空格隔开
输出不应包含多余的空行和空格

样例

样例输入

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 3 3个传递情报任务,都是经过 5 5 5名情报员,分别是 4 4 4号、 2 2 2号、 1 1 1号、 3 3 3号和 7 7 7
其中,对于第 1 1 1个任务,所有情报员(危险值为 0 0 0)都不对情报构成威胁
对于第 2 2 2个任务,有 2 2 2名情报员对情报构成威胁,分别是 1 1 1号情报员(危险值为 3 3 3)和 4 4 4号情报员(危险值为 2 2 2), 7 7 7号情报员(危险值为 1 1 1)并不构成威胁
对于第 3 3 3个任务,只有 1 1 1名情报员对情报构成威胁

数据范围

对于 30 % 30\% 30%的数据,只包含传递情报任务
另有 30 % 30\% 30%的数据,保证传递情报任务中 C i C_i Ci等于 0 0 0
对于 100 % 100\% 100%的数据, n ⩽ 2 × 1 0 5 , q ⩽ 2 × 1 0 5 , 0 ⩽ P i , C i ⩽ n , 1 ⩽ T i , X i , Y i ⩽ n n\leqslant 2\times 10^5,q\leqslant 2\times 10^5,0\leqslant P_i,C_i\leqslant n,1\leqslant T_i,X_i,Y_i\leqslant n n2×105q2×1050PiCin1TiXiYin

题解

首先,题目相当于要求我们回答两个问题:

  1. 两个点之间的链的长度
  2. 两个点之间的链上有多少个数大于 c c c

第一个问题极其简单,直接计算 d e p x + d e p y − 2 × d e p l c a ( x , y ) + 1 dep_x+dep_y-2\times dep_{lca(x,y)}+1 depx+depy2×deplca(x,y)+1就可以了
对于第二个问题,我们可以先把所有数读入,再建一棵主席树,把所有的 2 2 2操作全部先做完,再同一回答询问
附上代码:

#include<algorithm>
#include<cstdio>
using namespace std;
int n,tot,Root,head[200010],nxt[400010],to[400010],dfn[200010],nfd[200010],Fa[200010][21],dep[200010];
int m,cnt,root[200010],T[200010];
struct ppap
{
	int a,b,c,d;
}s[200010];
struct Segment_Tree
{
	int ls,rs,sum;
}t[4000010];
void add(int u,int v)
{
	nxt[++tot]=head[u],head[u]=tot,to[tot]=v;
}
void dfs(int x,int fa)
{
	dfn[x]=++cnt,nfd[cnt]=x,Fa[x][0]=fa,dep[x]=dep[fa]+1;
	for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa) dfs(to[i],x);
}
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=19;i>=0;i--) if(dep[x]-(1<<i)>=dep[y]) x=Fa[x][i];
	if(x==y) return x;
	for(int i=19;i>=0;i--) if(Fa[x][i]!=Fa[y][i]) x=Fa[x][i],y=Fa[y][i];
	return Fa[x][0];
}
void change(int &p,int fa,int l,int r,int d)
{
	if(!p) p=++cnt;
	if(l==r){t[p].sum=t[fa].sum+1;return;}
	int mid=(l+r)>>1;
	if(d<=mid) change(t[p].ls,t[fa].ls,l,mid,d),t[p].rs=t[fa].rs;
	else change(t[p].rs,t[fa].rs,mid+1,r,d),t[p].ls=t[fa].ls;
	t[p].sum=t[t[p].ls].sum+t[t[p].rs].sum;
}
int ask(int b,int c,int LCA,int fa,int l,int r,int L,int R)
{
	if(L<=l&&R>=r) return t[b].sum+t[c].sum-t[LCA].sum-t[fa].sum;
	int mid=(l+r)>>1,ans=0;
	if(L<=mid) ans=ask(t[b].ls,t[c].ls,t[LCA].ls,t[fa].ls,l,mid,L,R);
	if(R>mid) ans+=ask(t[b].rs,t[c].rs,t[LCA].rs,t[fa].rs,mid+1,r,L,R);
	return ans;
}
int main()
{
	freopen("message.in","r",stdin);
	freopen("message.out","w",stdout);
	scanf("%d",&n);
	for(int i=1,x;i<=n;i++){
		scanf("%d",&x);
		if(!x) Root=i;
		else add(x,i),add(i,x);
	}
	dfs(Root,0);
	for(int j=1;j<=19;j++) for(int i=1;i<=n;i++) Fa[i][j]=Fa[Fa[i][j-1]][j-1];
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d",&s[i].a,&s[i].b);
		if(s[i].a==1) scanf("%d%d",&s[i].c,&s[i].d);
		if(s[i].a==2) T[s[i].b]=i;
	}
	for(int i=1;i<=n;i++) change(root[nfd[i]],root[Fa[nfd[i]][0]],0,m,T[nfd[i]]);
	for(int i=1;i<=m;i++){
		if(s[i].a==2) continue;
		int LCA=lca(s[i].b,s[i].c);
		printf("%d ",dep[s[i].b]+dep[s[i].c]-dep[LCA]*2+1);
		if(i-s[i].d-1<1) printf("0\n");
		else printf("%d\n",ask(root[s[i].b],root[s[i].c],root[LCA],root[Fa[LCA][0]],0,m,1,i-s[i].d-1));
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值