题目

其实 Kano 曾经到过由乃山,当然这名字一看山主就是 Yuno 嘛。当年 Kano 看见了由乃山,内心突然涌出了一股杜甫会当凌绝顶,一览众山小的豪气,于是毅然决定登山。

但是 Kano 总是习惯性乱丢垃圾,增重环卫工人的负担,Yuno 并不想让 Kano 登山,于是她果断在山上设置了结界……

Yuno 为了方便登山者,在山上造了 N 个营地,编号从 0 开始。当结界发动时,每当第 i(>0)号营地内有人,那么他将被传送到第 Ai(<i)号营地,如此循环,所以显然最后只会被传送到第 0 号营地。

但 Kano 并不知晓结界的情况。他登山的方法是这样的:首先分身出一个编号为 Gi 的 Kano,然后将其用投石机抛掷到营地 Di。Kano 总共做了 M 次这样的登山操作,但每次抛出去的 Kano 都被传送回了营地 0,所以 Kano 只好放弃了。

但是 Kano 在思考一个问题,到底每个营地被多少只编号不同的 Kano 经过过?

输入格式

第一行两个整数 N,M,表示山的营地数和登山次数。

接下来 N−1 行,每行一个数,第 i 行为 Ai,表示营地 i 将会传向营地 Ai。

接下来 M 行,每行两个数 Di,Gi。

输出格式

共 N 行,每行表示营地 i 有多少不同编号的 Kano 曾经通过。

样例数据

Input

5 4
0
0
1
1
4 1
3 1
2 2
4 2

Output

2
2
1
1
2

样例解释

1 号 Kano 曾被抛到 3,4 两个营地,传送轨迹分别是 3−1−0, 4−1−0

2 号 Kano 曾被抛到 2,4 两个营地,传送轨迹分别是 2−0, 4−1−0

所以 0,1,4 号营地被两只 Kano 经过过,2,3 号营地被一只 Kano 经过过。

数据规模与约定

\(5≤N≤100000,10≤M≤100000,max(Gi)≤1000000000\)

时间限制:1s

空间限制:512MB

思路

首先来想一想本题的暴力解法.

很直观的思路是对每一个营地用数组(或\(vector\)/\(set\)/\(queue\)/线段树/平衡树)维护一个集合,存放到达过该点的\(Kano\)的编号.当第\(i\)号营地里的\(Kano\)被传送到第\(A_i\)号营地时,把维护的第\(i\)号营地的集合合并到第\(A_i\)号营地的集合里.最后,每个营地的集合去重后的大小,就是曾经经过了该营地的不同编号的\(Kano\)的数量.

这样就有两个问题:一是合并的顺序;二是怎么合并两个数据结构.

第一个问题很好回答:我们可以倒序从\(n\)到\(1\)遍历序列,每次计算出该营地的答案,同时把该营地的数据合并到\(A_i\)营地.这是因为\(A_i<i\),也就是说,无论哪次合并,都是"从后面的某个营地合并到前面的某个营地".换句话说,一个营地的状态,只与它和它后面的某些营地有关.

第二个问题也很好回答,只需要按照启发式合并的思想,每次都将小的集合合并到大的集合,这样可以获得优秀的\(O(nlog_2n)\)的时间复杂度.

在代码实现中我使用了\(STL-set\),以省去去重的环节.

代码

#include<cstdio>
#include<set>
using namespace std;
int n,A[100005],m,G,D,Ans[100005],ID[100005];
set<int>x[100005];
inline void Merge(int u,int v){
if(x[ID[u]].size()<x[ID[v]].size())swap(ID[u],ID[v]);//启发式合并
for(set<int>::iterator it=x[ID[v]].begin();it!=x[ID[v]].end();it++)
x[ID[u]].insert(*it);
}
int main(){
scanf("%d%d",&n,&m);
for(int i=2;i<=n;i++){ scanf("%d",&A[i]); A[i]++; }
for(int i=1;i<=n;i++)ID[i]=i;
while(m--){ scanf("%d%d",&G,&D); x[ID[G+1]].insert(D); }
for(int i=n;i;i--){ Ans[i]=x[ID[i]].size(); if(A[i])Merge(A[i],i); }//将 i 合并到 A[i]
for(int i=1;i<=n;i++)printf("%d\n",Ans[i]);
return 0;
}

总结

如果把题给的条件看成\(<i,A_i>\)的有向边,那么可以建出一个\(DAG\)图,而上面提到的倒序从\(n\)到\(1\)就是该图的一个拓扑序,因此我们可以倒着合并.

爬山 启发式合并 / STL的更多相关文章

  1. [NOI2015] 品酒大会 - 后缀数组,并查集,STL,启发式合并

    [NOI2015] 品酒大会 Description 对于每一个 \(i \in [0,n)\) 求有多少对后缀满足 LCP 长度 \(\le i\) ,并求满足条件的两个后缀权值乘积的最大值. So ...

  2. 【BZOJ1483】【HNOI2009】梦幻布丁(启发式合并,平衡树)

    [BZOJ1483][HNOI2009]梦幻布丁 题面 题目描述 N个布丁摆成一行,进行M次操作.每次将某个颜色的布丁全部变成另一种颜色的,然后再询问当前一共有多少段颜色.例如颜色分别为1,2,2,1 ...

  3. [bzoj3123][sdoi2013森林] (树上主席树+lca+并查集启发式合并+暴力重构森林)

    Description Input 第一行包含一个正整数testcase,表示当前测试数据的测试点编号.保证1≤testcase≤20. 第二行包含三个整数N,M,T,分别表示节点数.初始边数.操作数 ...

  4. 【BZOJ3123】森林(主席树,启发式合并)

    题意:一个带点权的森林,要求维护以下操作: 1.询问路径上的点权K大值 2.两点之间连边 n,m<=80000 思路:如果树的结构不发生变化只需要维护DFS序 现在因为树的结构发生变化,要将两棵 ...

  5. BZOJ2888 资源运输(LCT启发式合并)

    这道题目太神啦! 我们考虑他的每一次合并操作,为了维护两棵树合并后树的重心,我们只好一个一个的把节点加进去.那么这样一来看上去似乎就是一次操作O(nlogn),但是我们拥有数据结构的合并利器--启发式 ...

  6. 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并

    启发式合并而已啦,, 调试时发现的错误点:insert后没有splay,把要拆开的树的点插入另一个树时没有把ch[2]和fa设为null,找第k大时没有先减k,,, 都是常犯的错误,比赛时再这么粗心就 ...

  7. 51nod 1515 明辨是非 并查集 + set + 启发式合并

    给n组操作,每组操作形式为x y p. 当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等:否则输出NO,并忽略此次操作. 当p为0时,如果第x变量和第y个变量可以不相等,则输 ...

  8. [BZOJ 1483][HNOI 2009]梦幻补丁(有序表启发式合并)

    题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1483 分析: 先将不同的颜色的出现位置从小到大用几条链表串起来,然后统计一下答案 对于 ...

  9. 【BZOJ-2809】dispatching派遣 Splay + 启发式合并

    2809: [Apio2012]dispatching Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2334  Solved: 1192[Submi ...

随机推荐

  1. 剑指offer-面试题23-链表中环的入口节点-双指针

    /* 题目: 如果链表中包含环,如何找出环的入口? */ /* 思路: 双指针: 1.判断是否有环. fast指针一次2步,slow指针一次1步,当fast与slow相遇时,说明有环. 2.判断环路中 ...

  2. 【3】Python中的广播

    Python-numpy中有一种很高效的方法:广播.  下面介绍一下广播. 实例:对于这个矩阵,如果想求每列元素的和,怎么才能不用for循环? (1,4)指的是一行四列的矩阵:axis决定了是横向(行 ...

  3. ASP.NET MVC中ActionResult的不同返回方式

    1.返回视图 return View();//返回方法名对应的视图 return View("aaa");//返回名称为aaa的视图 2.返回文本内容 return Content ...

  4. CQOI跳舞(网络流+二分答案)

    题面见 https://www.luogu.org/problemnew/show/P3153 题意简述:有n个男生,n个女生,每一首歌时两位男女配对,然后同一对男女只能跳一场,一个人只会与不喜欢的人 ...

  5. Tomcat报错Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

    问题描述:后台报错 Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.java ...

  6. 入门移动端混合开发 实战京东 APP(完整更新)

    课程资料获取链接:点击这里 混合开发入门 主流开发方案实战京东移动端APP 无需原生开发基础,也能完美呈现京东商城.本课程融合vue.Android.IOS等目前流行的前端和移动端技术,混合开发经典电 ...

  7. Linux vim三种模式的快捷键

    1.移动光标 数字 + h,j,k,l 上,下,左,右 ctrl-e 移动页面 ctrl-f 上翻一页 ctrl-b 下翻一页 ctrl-u 上翻半页 ctrl-d 下翻半页 w 跳到下一个字首,按标 ...

  8. java开发就业招聘管理系统 ssh源码

    开发环境:    Windows操作系统开发工具: MyEclipse+Jdk+Tomcat+MySql数据库 此项目分为 用户 企业  管理员三种角色 运行效果图

  9. JQ input输入框回车生成标签,可删除,并获取标签的值

    在网上找的,效果如下 html代码 <!DOCTYPE html> <html lang="zh-CN"> <head> <title&g ...

  10. VSCode常用插件之vscode-fileheader使用

    更多VSCode插件使用请访问:VSCode常用插件汇总 vscode-fileheader这是一个给js文件(html.css也可以使用,但是没意义!!!)生成头部注释的插件,每次修改js文件之后会 ...