您的位置:首页 > 其它

4448: [Scoi2015]情报传递

2017-02-14 14:41 323 查看

4448: [Scoi2015]情报传递

Time Limit: 20 Sec Memory Limit: 256 MB

Submit: 565 Solved: 290

[Submit][Status][Discuss]

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

HINT

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

任务,所有情报员(危险值为0)都不对情报构成威胁;对于第2个任务,有2名情报员对情报构成威胁,

分别是1号情报员(危险值为3)和4号情报员(危险值为2),7号情报员(危险值为1)并不构成威胁;

对于第3个任务,只有1名情报员对情报构成威胁。

n< = 2×10^5,Q< = 2×105,0< Pi,C!< = N, 1< = Ti,Xi,Yi< = n

题解:JudgeOnline/upload/201603/Solution-4448.rar

Source



[Submit][Status][Discuss]

设第i个传递任务是于时间Di发布,风险控制值Ci
设第j个情报员第一次接到搜集任务的时间为Ei
那么,对于第i个传递任务,路径上满足Di - Ci > Ej的所有情报员j都对该任务构成威胁
可以把每条路径拆成两条链,就变成求链上某区间小于某值的数字的数量
把主席树搬到树上就解决了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;

const int maxn = 2E5 + 20;
const int T = 20;

int n,m,cnt,root,rt[maxn],L[maxn],A[maxn],B[maxn],C[maxn],D[maxn],E[maxn],typ[maxn],siz[maxn*T],lc[maxn*T],rc[maxn*T],fa[maxn][T];

vector <int> v[maxn];

int getint()
{
char ch = getchar(); int ret = 0;
while (ch < '0' || '9' < ch) ch = getchar();
while ('0' <= ch && ch <= '9')
ret = ret * 10 + ch - '0',ch = getchar();
return ret;
}

int Insert(int l,int r,int o,int k)
{
int ret = ++cnt; siz[cnt] = siz[o] + 1;
if (l == r) return ret;
int mid = (l + r) >> 1;
if (k <= mid) lc[ret] = Insert(l,mid,lc[o],k),rc[ret] = rc[o];
else rc[ret] = Insert(mid+1,r,rc[o],k),lc[ret] = lc[o];
return ret;
}

void Dfs(int x)
{
rt[x] = Insert(0,m + 1,rt[fa[x][0]],E[x]);
for (int i = 1; i < T; i++) fa[x][i] = fa[fa[x][i-1]][i-1];
for (int i = 0; i < v[x].size(); i++)
{
int to = v[x][i]; L[to] = L[x] + 1;
fa[to][0] = x; Dfs(to);
}
}

int query(int l,int r,int o1,int o2,int k)
{
if (r < k) return siz[o1] - siz[o2];
int mid = (l + r) >> 1,ret = 0;
if (k > mid + 1) ret = query(mid+1,r,rc[o1],rc[o2],k);
return ret + query(l,mid,lc[o1],lc[o2],k);
}

int Query(int x,int y,int k)
{
if (k <= 0) return 0;
return query(0,m + 1,rt[x],rt[fa[y][0]],k);
}

int LCA(int p,int q)
{
if (L[p] < L[q]) swap(p,q);
for (int i = T - 1; i >= 0; i--)
if (L[p] - (1 << i) >= L[q]) p = fa[p][i];
if (p == q) return p;
for (int i = T - 1; i >= 0; i--)
if (fa[p][i] != fa[q][i])
p = fa[p][i],q = fa[q][i];
return fa[p][0];
}

int Quickfa(int x,int y)
{
for (int now = 0; y; y >>= 1,now++)
if (y & 1) x = fa[x][now];
return x;
}

int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif

n = getint();
for (int i = 1; i <= n; i++)
{
int x = getint();
if (!x) root = i;
else v[x].push_back(i);
}
m = getint();
for (int i = 1; i <= m; i++)
{
typ[i] = getint();
if (typ[i] == 1)
{
A[i] = getint(); B[i] = getint();
C[i] = getint(); D[i] = i;
}
else {int x = getint(); if (!E[x]) E[x] = i;}
}
for (int i = 1; i <= n; i++) if (!E[i]) E[i] = m + 1;
L[root] = 1; Dfs(root);

for (int i = 1; i <= m; i++)
if (typ[i] == 1)
{
int lca = LCA(A[i],B[i]),Ans1,Ans2;
Ans1 = L[A[i]] + L[B[i]] - 2 * L[lca] + 1;
Ans2 = Query(A[i],lca,D[i] - C[i]);
if (B[i] != lca) Ans2 += Query(B[i],Quickfa(B[i],L[B[i]] - L[lca] - 1),D[i] - C[i]);
printf("%d %d\n",Ans1,Ans2);
}
return 0;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: