Kattis - boxes (LCA)
Boxes
There are NN boxes, indexed by a number from 11 to NN. Each box may (or not may not) be put into other boxes. These boxes together form a tree structure (or a forest structure, to be precise).
You have to answer a series of queries of the following form: given a list of indices of the boxes, find the total number of boxes that the list of boxes actually contain.
Consider, for example, the following five boxes.
Figure 1: Sample input
If the query is the list “1”, then the correct answer is “5”, because box 1 contains all boxes.
If the query is the list “4 5”, then the correct answer is “2”, for boxes 4 and 5 contain themselves and nothing else.
If the query is the list “3 4”, then the correct answer is “2”.
If the query is the list “2 3 4”, then the correct answer is “4”, since box 2 also contains box 5.
If the query is the list “2”, then the correct answer is “3”, because box 2 contains itself and two other boxes.
Input
The first line contains the integer NN (1≤N≤2000001≤N≤200000), the number of boxes.
The second line contains NNintegers. The iith integer is either the index of the box which contains the iith box, or zero if the iith box is not contained in any other box.
The third line contains an integer QQ (1≤Q≤1000001≤Q≤100000), the number of queries. The following QQ lines will have the following format: on each line, the first integer MM(1≤M≤201≤M≤20) is the length of the list of boxes in this query, then MM integers follow, representing the indices of the boxes.
Output
For each query, output a line which contains an integer representing the total number of boxes
Sample Input 1
5
0 1 1 2 2
5
1 1
2 4 5
2 3 4
3 2 3 4
1 2
Sample Output 1
5
2
2
4
3
题意是给你n个盒子,它们之间互相嵌套,给你m个询问,每次问你cnt个盒子中一共有几个盒子。
显然盒子的嵌套关系可以转换成树的父子关系。假设询问中有1 2 号盒子,而且1号盒子包含了2号盒子,这时2号盒子就被cover掉了,我们统计时只统计没有被cover的盒子就行了。
这就转换成了给你cnt个点,去掉其中含有所有父子关系中的儿子们,剩下的点输出他们的孩子一共有多少就可以了。
#include <bits/stdc++.h> using namespace std;
const int maxn =+;
vector <int> son[maxn];//存儿子
int fa[maxn][];//fa[i][j]表示 节点i向上走2^j个节点会到达哪个节点
int p[maxn];//模拟的队列
int sum[maxn];//每个节点的子树(包括自己)的节点数目
int dep[maxn];//每个节点深度
int inp[];//询问的点们
bool iip[];//是否被覆盖
int n,m;
void bfs(int x)
{
dep[x]=;
int w,r;//w r 分别是队首队尾的下标
w=;
p[]=x;//模拟的队首是x
sum[x]=;
r=;//队尾下标是1
while(w<=r)//队首下标小于等于队尾下标,即队列非空
{
int u=p[w];w++;//去队首,pop队首
for(unsigned int i=;i<son[u].size();i++)//遍历当前节点的每一个儿子
{
int v=son[u][i];
if(dep[v])continue;//如果当前节点的深度不是0,就是被访问过,continue
dep[v]=dep[u]+;//当前节点深度等于父节点深度+1
sum[v]=;//当前节点的子树节点数为1
p[++r]=v;//将当前节点push到队列中去
}
}
/* 由于我们是按照数组保存的队列,我们从最大的下标(此时这些节点的深度也是最大的一批)
开始向上回溯,让他们的父节点的sum加上他们的sum
*/
while(r>)
{
sum[fa[p[r]][]]+=sum[p[r]];
r--;
}
}
int findd(int x,int y)
{
if (x!=y&&dep[x]==dep[y]) return false;
if (x==y) return true;
if (dep[x]<dep[y]){int temp=x;x=y;y=temp;}//保证dep[x]>=dep[y]
while (dep[x]>dep[y]){//从x往上跳,跳的步数为1,2,4,8...
int j=;
while (dep[fa[x][j]]>dep[y]) ++j;
if (dep[fa[x][j]]==dep[y]){x=fa[x][j];break;}//如果跳到了同一深度,更新下x
x=fa[x][--j];//让x跳到深度<=y而且深度最大的节点
}
if (x==y)
return y;//如果此时x==y,则y是x的父亲,x,y的LCA显然是y
while (x!=y){
int j=;
while (fa[x][j]!=fa[y][j]) ++j;//x,y一起往上跳,直至两个跳到同一个点
if (j==)//此时x,y是亲兄弟
break;
--j;
x=fa[x][j],y=fa[y][j];
}
return fa[x][];
}
int main()
{
//freopen("de.txt","r",stdin);
while (~scanf("%d",&n)){
for (int i=;i<=n;++i){
scanf("%d",&fa[i][]);
son[fa[i][]].push_back(i);
}
for (int j=,k=;k<=n;++j,k*=){
for (int i=;i<=n;++i)
fa[i][j]=fa[fa[i][j-]][j-];
/* i向上走2^j个点等于 i向上走2^(j-1)个点后再向上走2^(j-1)个点 */
}
memset(sum,,sizeof sum);
memset(dep,,sizeof dep);
bfs();//广搜
/*printf("sum ");
for (int i=0;i<=n;++i)
printf("%d ",sum[i]);
printf("\n");*/
scanf("%d",&m);
while (m--){
int tot=;
int cnt;
memset(inp,,sizeof inp);
memset(iip,false,sizeof iip);
scanf("%d",&cnt);
for (int i=;i<=cnt;++i)
scanf("%d",&inp[i]);
for (int i=;i<=cnt-;++i){
if (iip[i]) continue;
for (int j=i+;j<=cnt;++j){
if (iip[j]) continue;
if (inp[i]==inp[j]){iip[j]=true;continue;}
int lca=findd(inp[i],inp[j]);
//printf("%d %d lca is %d\n",i,j,lca);
if (lca==) continue;
if (lca==inp[i]){iip[j]=true;continue;}
if (lca==inp[j]){iip[i]=true;continue;}
}
}
/*for (int i=1;i<=cnt;++i)
printf("!%d ",iip[i]);
printf("\n");*/
for (int i=;i<=cnt;++i)
if (!iip[i]){
//printf("cnt %d\n",inp[i]);
tot+=sum[inp[i]];
} printf("%d\n",tot);
}
}
return ;
}
Kattis - boxes (LCA)的更多相关文章
- 洛谷P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 152通过 532提交 题目提供者HansBug 标签 难度普及+/提高 提交 讨论 题解 最新讨论 为什么还是超时.... 倍增怎么70!!题解好像有 ...
- 图论--最近公共祖先问题(LCA)模板
最近公共祖先问题(LCA)是求一颗树上的某两点距离他们最近的公共祖先节点,由于树的特性,树上两点之间路径是唯一的,所以对于很多处理关于树的路径问题的时候为了得知树两点的间的路径,LCA是几乎最有效的解 ...
- hihoCoder 1233 : Boxes(盒子)
hihoCoder #1233 : Boxes(盒子) 时间限制:1000ms 单点时限:1000ms 内存限制:256MB Description - 题目描述 There is a strange ...
- 面试题6:二叉树最近公共节点(LCA)《leetcode236》
Lowest Common Ancestor of a Binary Tree(二叉树的最近公共父亲节点) Given a binary tree, find the lowest common an ...
- P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- 洛谷P3379 【模板】最近公共祖先(LCA)(dfs序+倍增)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- 「LuoguP3379」 【模板】最近公共祖先(LCA)
题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每 ...
- 洛谷——P3379 【模板】最近公共祖先(LCA)
P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...
- luogo p3379 【模板】最近公共祖先(LCA)
[模板]最近公共祖先(LCA) 题意 给一个树,然后多次询问(a,b)的LCA 模板(主要参考一些大佬的模板) #include<bits/stdc++.h> //自己的2点:树的邻接链表 ...
随机推荐
- ConcurrentHashMap1.7源码分析
参考:https://www.cnblogs.com/liuyun1995/p/8631264.html HashMap不是线程安全的,其所有的方法都未同步,虽然可以使用Collections的syn ...
- php strcasecmp()函数 语法
php strcasecmp()函数 语法 作用:比较两个字符串(不区分大小写)直线电机驱动器 语法:strcasecmp(string1,string2) 参数: 参数 描述 string1 必须, ...
- nIce 不看会后悔的o!
今天小编来跟大家探讨关于“控件”.控件非常好玩,可以构建出不同的场景和不同风格的Windows画面.相信大家绝对狠感兴趣是吧~~~ 好了,下面小编就为大家来展示风采喽 下面先为大家展示一些比较基础 ...
- IntelliJ IDEA更新maven依赖包
问题: IntelliJ IDEA自动载入Maven依赖的功能很好用,但有时候会碰到问题,导致pom文件修改却没有触发自动重新载入的动作,此时需要手动强制更新依赖. 方法: 方法一: ①.右键单击项目 ...
- ALM11服务器IP变更相关配置修改
最近项目新增了网络控制,需要把ALM服务器迁移到新的区域.服务器整体复制后更改了IP地址. ALM与Oracle在同一台服务器(windows server 2008 R2) ALM的配置也需要做如下 ...
- Nginx (限速)限制并发、限制访问速率、限制流量
Nginx 限制并发访问速率流量,配置还是简单的,看下Nginx文档根据文中这三个模块对照看一下就可以,Nginx限速使用的是漏桶算法(感兴趣可以看下文末的参考资料),需要注意的是:当需要进行限速操作 ...
- Jenkins构建触发器的区别
Build periodically:定时进行项目构建或执行(它不care源码是否发生变化),配置如下: 0 2 * * * (每天2:00 必须build一次源码) 如果是要定时执行脚本,需要选择 ...
- nginx相关总结
1. Nginx 无法启动解决方法 在查看到 logs 中报了如下错误时: 0.0.0.0:80 failed (10013: An attempt was made to access a sock ...
- <JAVA - 大作业(1)文本编辑器 >
<JAVA - 大作业(1)文本编辑器 > 背景 JAVA上机大作业:qq / 代码评价系统 第一次上机主题是练习JAVA自带的GUI图形化编程 目的:实现一个跟window10记事本界面 ...
- django-1-新手如何使用django
工具: python,django 流程: 1.安装python 安装python,配置python环境变量, 2.安装django django安装有两种方式: 1.通过pip安装(python2叫 ...