题目描述

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

输出

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

样例输入

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


题目大意

给出一棵树,有两种操作:1.标记一个点;2.询问两点间路径长度及路径上上有多少个点在 当前时间减去ci 之前被标记过

题解

主席树

看懂了题就好做多了。

考虑到修改操作比较麻烦,由于c>0,表明后面对前面没有影响,可以调换顺序。

我们可以离线处理,先将所有点标记上(即赋权值为标记时间),然后离线查找即可。

之后就是套路,点x在fa[x]之上建立主席树,查询x、y时相当于1->x + 1->y - 1->lca(x,y) - 1->fa[lca(x,y)]。

注意一下 当前时间-ci<=0 时的特判

#include <cstdio>
#include <algorithm>
#define N 200010
using namespace std;
int m , head[N] , to[N] , next[N] , cnt , fa[N][20] , deep[N] , log[N] , opt[N] , x[N] , y[N] , c[N] , p[N];
int root[N] , ls[N * 20] , rs[N * 20] , si[N * 20] , tot;
void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void ins(int p , int l , int r , int x , int &y)
{
y = ++tot , si[y] = si[x] + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) rs[y] = rs[x] , ins(p , l , mid , ls[x] , ls[y]);
else ls[y] = ls[x] , ins(p , mid + 1 , r , rs[x] , rs[y]);
}
void dfs(int x)
{
int i;
if(p[x]) ins(p[x] , 1 , m , root[fa[x][0]] , root[x]);
else root[x] = root[fa[x][0]];
for(i = 1 ; i <= log[deep[x]] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(i = head[x] ; i ; i = next[i]) deep[to[i]] = deep[x] + 1 , dfs(to[i]);
}
int getlca(int x , int y)
{
int i;
if(deep[x] < deep[y]) swap(x , y);
for(i = log[deep[x] - deep[y]] ; ~i ; i -- )
if(deep[x] - (1 << i) >= deep[y])
x = fa[x][i];
for(i = log[deep[x]] ; ~i ; i -- )
if(deep[x] >= (1 << i) && fa[x][i] != fa[y][i])
x = fa[x][i] , y = fa[y][i];
return x == y ? x : fa[x][0];
}
int query(int p , int l , int r , int a , int b , int c , int d)
{
if(l == r) return si[a] + si[b] - si[c] - si[d];
int mid = (l + r) >> 1;
if(p <= mid) return query(p , l , mid , ls[a] , ls[b] , ls[c] , ls[d]);
else return query(p , mid + 1 , r , rs[a] , rs[b] , rs[c] , rs[d]) + si[ls[a]] + si[ls[b]] - si[ls[c]] - si[ls[d]];
}
int main()
{
int n , i , f;
scanf("%d%*d" , &n);
for(i = 2 ; i <= n ; i ++ ) scanf("%d" , &fa[i][0]) , add(fa[i][0] , i) , log[i] = log[i >> 1] + 1;
scanf("%d" , &m);
for(i = 1 ; i <= m ; i ++ )
{
scanf("%d%d" , &opt[i] , &x[i]);
if(opt[i] == 1) scanf("%d%d" , &y[i] , &c[i]);
else if(!p[x[i]]) p[x[i]] = i;
}
dfs(1);
for(i = 1 ; i <= m ; i ++ )
if(opt[i] == 1)
f = getlca(x[i] , y[i]) , printf("%d %d\n" , deep[x[i]] + deep[y[i]] - 2 * deep[f] + 1 , i - c[i] > 0 ? query(i - c[i] - 1 , 1 , m , root[x[i]] , root[y[i]] , root[f] , root[fa[f][0]]) : 0);
return 0;
}

【bzoj4448】[Scoi2015]情报传递 主席树的更多相关文章

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

    题目描述 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有n名情报员.每名情报员口J-能有 若T名(可能没有)下线,除1名大头目外其余n-1名情报员有且仅有1名上线.奈特公司纪律森严 ...

  2. bzoj4448 [Scoi2015]情报传递 主席树+树上差分

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4448 题解 练习一下主席树的基础练习题找回感觉. 对于每一次询问,第一问显然随便做. 第二问的 ...

  3. 【BZOJ4448】[Scoi2015]情报传递 主席树+LCA

    [BZOJ4448][Scoi2015]情报传递 Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络.情报网络中共有n名情报员.每名情报员能有若干名(可能没有)下线,除1名大头 ...

  4. bzoj 4448 [Scoi2015]情报传递 主席树

    比较套路的题目. 可以发现难点在于某个点的权值动态修改 且我们要维护树上一条路径上的点权>x的个数. 每个点都在动态修改 这意味着我们的只能暴力的去查每个点. 考虑将所有可以动态修改的点变成静态 ...

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

    能够把全部的操作离线,然后树链剖分将全部人搜集情报的时间增加到主席树中,查询的时候能够直接查询搜集情报时间≤i−C[i]−1的人的个数 时间复杂度n∗log22n,空间复杂度n∗log2n #incl ...

  6. BZOJ4448 SCOI2015情报传递(离线+树链剖分+树状数组)

    即滋磁单点修改,询问路径上小于某数的值有多少个.暴力树剖套个主席树(或者直接树上主席树,似乎就1个log了?感觉不一定比两个log快)即可,然而不太优美. 开始觉得可以cdq,然而就变成log^3了. ...

  7. 洛谷P4216 [SCOI2015]情报传递(树剖+主席树)

    传送门 我们可以进行离线处理,把每一个情报员的权值设为它开始收集情报的时间 那么设询问的时间为$t$,就是问路径上有多少个情报员的权值小于等于$t-c-1$ 这个只要用主席树上树就可以解决了,顺便用树 ...

  8. bzoj4448 SCOI2015 情报传递 message

    传送门bzoj4448 题解 离线之后构建树上主席树,每个点的线段树维护到根路径的信息,不用链剖(我的链剖只是拿来求\(\mathrm{lca}\)的),时空复杂度\(O(n\log{n})\). c ...

  9. 2019.03.26 bzoj4448: [Scoi2015]情报传递(归并排序+树链剖分)

    传送门 题意简述: 给一棵nnn个点的树,树上每个点表示一个情报员,一共有mmm天,每天会派发以下两种任务中的一个任务: 1.搜集情报:指派T号情报员搜集情报 2.传递情报:将一条情报从X号情报员传递 ...

随机推荐

  1. 2018.6.20 Java考试试题总结(Java语言基础与面向对象编程)最新版

    Java考试试题总结 一.单选题(每题1分 * 50 = 50分) 1.java程序的执行过程中用到一套JDK工具,其中javac.exe指( B ) A.java语言解释器 B.java字节码编译器 ...

  2. CentOS6.5-DHCP配置

    原文链接主机配置: 1.查看主机名:hostname 2.修改主机名:vi /etc/sysconfig/network NETWORKING=yes HOSTNAME=master.303kfy.n ...

  3. Websocket教程SpringBoot+Maven整合

    1.大话websocket及课程介绍 简介: websocket介绍.使用场景分享.学习课程需要什么基础 2.课程技术选型和浏览器兼容讲解 简介: 简单介绍什么是springboot.socketjs ...

  4. Oracle 汇总函数

    汇总函数,也叫统计函数.聚合函数.分组函数 汇总函数必须跟 group by 语句一起使用,对数据进行分组汇总. ① 求和:sum(col).列必须是数值. ② 最小值:min(col).列可以是数值 ...

  5. 防止sql注入方法 如何防止java中将MySQL的数据库验证密码加上 ' or '1'= '1 就可以出现万能密码 的PreparedStatement

    package com.swift; import java.sql.Connection; import java.sql.DriverManager; import java.sql.Prepar ...

  6. testC-I

    总时间限制:  20000ms 单个测试点时间限制:  1000ms 内存限制:  128000kB 描述 给你一组数,a1,a2,a3,⋯,an. 令:G=gcd(a1,a2,a3,⋯,an) 现在 ...

  7. 转:CentOS7 下 Redis4 安装与配置教程(Redis开机启动)

    转 https://ken.io/note/centos7-redis4-setup 一.前言 1.本教程主要内容 Redis安装与测试 Redis远程访问配置 Redis开机启动配置 2.本教程环境 ...

  8. 十三、MySQL WHERE 子句

    MySQL WHERE 子句 我们知道从 MySQL 表中使用 SQL SELECT 语句来读取数据. 如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句中. 语法 以下是 ...

  9. PHP 对象基础知识

    最近开始重新学习对象知识,其实也算是初步深入学习对象和设计模式,希望自己会坚持下去,保持更新 初识PHP对象 还记得,刚开始学习 PHP 的时候,学到到方法和对象时有一个很大的疑问,对象与方法相比较那 ...

  10. win10.net 安装出问题0x800F70422

    因为安装ooracle数据库的时候需要用到.net但安装的时候出了0x800F70422, 随后就去网上查了下这个错出现的原因,发现是我之前把Windows自带的更新给禁用了 只要把它再开启就行了.