bzoj 4448 情报传递
Written with StackEdit.
Description
奈特公司是一个巨大的情报公司,它有着庞大的情报网络。情报网络中共有\(n\)名情报员。每名情报员能有若干名(可能没有)下线,除\(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\)号情报员上线的编号。特别地,若\(P_i=0\),表示\(i\)号情报员是大头目。
第\(3\)行包含\(1\)个正整数\(q\),表示奈特公司将派发\(q\)个任务(每天一个)。
随后\(q\)行,依次描述\(q\)个任务。
每行首先有\(1\)个正整数\(k\)。若\(k=1\),表示任务是传递情报,随后有3个正整数\(X_i、Y_i、C_i\),依次表示传递情报的起点、终点和风险控制值;
若\(k=2\),表示任务是搜集情报,随后有\(1\)个正整数\(T_i\),表示搜集情报的情报员编号。
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
\(n< = 2×10^5,Q< = 2×105,0< P_i,C_i< = N, 1< = T_i,X_i,Y_i< = n.\)
Solution
- 第一问求\(LCA\),第二问对树上路径查询,显然先来一个树链剖分.
- 考虑如何解决第二问.情报员第一次被指派时,给一个当前时间\(i\)作为权值.
- 那么每次询问,若询问的时间为\(i\),则只需要询问路径上权值\(\leq i-C-1\)的点有多少个.使用树链剖分后,即为询问区间上某个数的排名.
- 那么只需要维护一颗树套树即可(在线比较方便),外层可以选用树状数组,因为这里询问个数是可以直接用前缀和相减的.
#include<bits/stdc++.h>
const int inf=1e9;
using namespace std;
typedef long long LoveLive;
inline int read()
{
int out=0,fh=1;
char jp=getchar();
while ((jp>'9'||jp<'0')&&jp!='-')
jp=getchar();
if (jp=='-')
{
fh=-1;
jp=getchar();
}
while (jp>='0'&&jp<='9')
{
out=out*10+jp-'0';
jp=getchar();
}
return out*fh;
}
const int MAXN=2e5+10;
int idx=0;
int x,y,z,r,p,q;
struct node{
int lson,rson,key,siz,weight;
}treap[MAXN*20];
struct FhqTreap{
int root;
FhqTreap()
{
treap[0].lson=treap[0].rson=treap[0].siz=0;
root=0;
}
#define rt treap[o]
#define ls treap[treap[o].lson]
#define rs treap[treap[o].rson]
inline int newnode(int key)
{
int o=++idx;
rt.lson=rt.rson=0;
rt.key=key;
rt.siz=1;
rt.weight=rand();
return o;
}
void pushup(int o)
{
rt.siz=ls.siz+rs.siz+1;
}
int BuildTree(int l,int r)
{
if(l>r)
return 0;
int mid=(l+r)>>1;
int o=newnode(inf);
rt.lson=BuildTree(l,mid-1);
rt.rson=BuildTree(mid+1,r);
pushup(o);
return o;
}
void split(int &x,int &y,int val,int o)
{
if(!o)
x=y=0;
else
{
if(val<rt.key)
{
y=o;
split(x,rt.lson,val,rt.lson);
}
else
{
x=o;
split(rt.rson,y,val,rt.rson);
}
pushup(o);
}
}
int merge(int X,int Y)
{
if(X==0 || Y==0)
return X+Y;
if(treap[X].weight<treap[Y].weight)
{
treap[X].rson=merge(treap[X].rson,Y);
pushup(X);
return X;
}
else
{
treap[Y].lson=merge(X,treap[Y].lson);
pushup(Y);
return Y;
}
}
void ins(int val)
{
int o=newnode(val);
root=merge(root,o);
}
int count(int lim)//<=lim
{
split(x,y,lim,root);
int res=treap[x].siz;
root=merge(x,y);
return res;
}
};
int n,m;
FhqTreap bit[MAXN];
#define lowbit(X) X&(-X)
void add(int X,int c)
{
for(;X<=n+1;X+=lowbit(X))
{
bit[X].ins(c);
}
}
int sum(int X,int lim)
{
int res=0;
for(;X;X-=lowbit(X))
res+=bit[X].count(lim);
return res;
}
int cnt=0,head[MAXN];
int nx[MAXN<<1],to[MAXN<<1];
inline void addedge(int u,int v)
{
++cnt;
to[cnt]=v;
nx[cnt]=head[u];
head[u]=cnt;
}
void insedge(int u,int v)
{
addedge(u,v);
addedge(v,u);
}
int dfn[MAXN],tid[MAXN],dfnidx=0;
int fa[MAXN],top[MAXN],dep[MAXN];
int siz[MAXN],mxson[MAXN];
void dfs1(int u,int Fa)
{
siz[u]=1;
fa[u]=Fa;
dep[u]=dep[Fa]+1;
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v!=Fa)
{
dfs1(v,u);
if(siz[v]>siz[mxson[u]])
mxson[u]=v;
siz[u]+=siz[v];
}
}
}
void dfs2(int u,int tp)
{
dfn[u]=++dfnidx;
tid[dfnidx]=u;
top[u]=tp;
if(mxson[u])
dfs2(mxson[u],tp);
for(int i=head[u];i;i=nx[i])
{
int v=to[i];
if(v!=fa[u] && v!=mxson[u])
dfs2(v,v);
}
}
int LCA(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
int query(int u,int v,int lim)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
res+=sum(dfn[u],lim)-sum(dfn[top[u]]-1,lim);
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
res+=sum(dfn[u],lim)-sum(dfn[v]-1,lim);
return res;
}
int vis[MAXN];
int main()
{
srand(time(NULL));
n=read();
int root;
for(int i=1;i<=n;++i)
{
int p=read();
if(!p)
root=i;
else
insedge(i,p);
}
dfs1(root,0);
dfs2(root,root);
m=read();
for(int i=1;i<=m;++i)
{
int op=read();
if(op==1)
{
int u=read(),v=read(),c=read();
int lca=LCA(u,v);
int ans1=dep[u]+dep[v]-2*dep[lca]+1;
int ans2=query(u,v,i-c-1);
printf("%d %d\n",ans1,ans2);
}
else
{
int t=read();
if(!vis[t])
{
add(dfn[t],i);
vis[t]=1;
}
}
}
return 0;
}
bzoj 4448 情报传递的更多相关文章
- BZOJ 4448: [Scoi2015]情报传递 树链剖分 主席树
4448: [Scoi2015]情报传递 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4448 Description 奈特公司是一个巨 ...
- bzoj 4448 [Scoi2015]情报传递(主席树,LCA)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4448 [题意] 给定一颗树,询问一条路径上权值小于t-c的点数. [思路] 将一个2查 ...
- bzoj 4448 [Scoi2015]情报传递 (树链剖分+主席树)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4448 题面: Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络 ...
- bzoj 4448: [Scoi2015]情报传递
Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有n名情报员.每名情报员口J-能有 若T名(可能没有)下线,除1名大头日外其余n-1名情报员有且仅有1名上线.奈 ...
- 洛谷 4216 BZOJ 4448 [SCOI2015]情报传递
[题解] 每个情报员的危险值val[i]应该是一个分段函数,前面一段是平行于x轴的横线,后面一段是一次函数.我们可以用fx(t)=t-b[x]表示这个一次函数.每次询问一条链上fx(t)大于c的点的个 ...
- bzoj 4448 [Scoi2015]情报传递 主席树
比较套路的题目. 可以发现难点在于某个点的权值动态修改 且我们要维护树上一条路径上的点权>x的个数. 每个点都在动态修改 这意味着我们的只能暴力的去查每个点. 考虑将所有可以动态修改的点变成静态 ...
- dfs序+主席树 或者 树链剖分+主席树(没写) 或者 线段树套线段树 或者 线段树套splay 或者 线段树套树状数组 bzoj 4448
4448: [Scoi2015]情报传递 Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 588 Solved: 308[Submit][Status ...
- BZOJ 4448 主席树+树链剖分(在线)
为什么题解都是离线的-- (抄都没法抄) 搞一棵主席树 1 操作 新树上的当前节点设成1 2 操作 查max(i-xx-1,0)那棵树上这条路径上有多少个点是1 让你找经过了多少个点 查的时候用dee ...
- BZOJ [Scoi2015]情报传递
Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有n名情报员.每名情报员口J-能有 若T名(可能没有)下线,除1名大头日外其余n-1名情报员有且仅有1名上线.奈 ...
随机推荐
- hadoop10---消息队列
java消息队列 BlockingQueue也是java.util.concurrent下的主要用来控制线程同步的工具.锁也是用来控制线程同步的,释放锁的时候谁拿到了锁是没有预测的,所以谁拿到了锁是不 ...
- MPU6050工作原理及STM32控制MPU6050
源:MPU6050工作原理及STM32控制MPU6050 MPU6050 介绍
- Python3:数字类型和字符串类型的相互转换
Python3:数字类型和字符串类型的相互转换 一.python中字符串转换成数字 方法1: 类中进行导入:import string str='555'num=string.atoi(str)num ...
- Python3.x:获取登录界面校验码图片
Python3.x:获取登录界面校验码图片 实例代码: # python3 # author lizm # datetime 2018-06-01 18:00:00 # -*- coding: utf ...
- 20165101刘天野 2018-2019-2《网络对抗技术》Exp4 恶意代码分析
20165101刘天野 2018-2019-2<网络对抗技术>Exp4 恶意代码分析 1. 实践目标 1.1是监控你自己系统的运行状态,看有没有可疑的程序在运行. 1.2是分析一个恶意软件 ...
- Maven 的41种骨架功能介绍
1: internal -> appfuse-basic-jsf (创建一个基于Hibernate,Spring和JSF的Web应用程序的原型) 2: internal -> appfu ...
- quartz(3)--spring整合quartz入门案例
第一步:导入jar <!-- quartz --> <dependency> <groupId>org.quartz-scheduler</groupId&g ...
- ViewPager实现图片的轮播
在app中图片的轮播显示可以说是非常常见的实现效果了,其实现原理不过是利用ViewPager,然后利用handler每隔一定的时间将ViewPager的currentItem设置为当前item的pos ...
- 比较好的SQL语句
批次导数据表头 SELECT [运单号] , [运单号] AS [订单号] , [运单号] AS [订单号] , [运单号] , SUM([price] * [ProductNum]) AS [订单总 ...
- NumPy数组创建例程
NumPy - 数组创建例程 新的ndarray对象可以通过任何下列数组创建例程或使用低级ndarray构造函数构造. numpy.empty 它创建指定形状和dtype的未初始化数组. 它使用以下构 ...