题目

其实 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. openlayers轨迹匀速播放

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. appium 爬取微信的相册内容(不知什么时候能写完)

    # crowl wechat through appium from appium import webdriver from selenium.webdriver.support.ui import ...

  3. hdu6212 Zuma(区间dp)

    #pragma GCC optimize(2) #include <bits/stdc++.h> #define ll long long #define ls(i) i<<1 ...

  4. JavaDay10(上)

    Java learning_Day10(上) 本人学习视频用的是马士兵的,也在这里献上 <链接:https://pan.baidu.com/s/1qKNGJNh0GgvlJnitTJGqgA&g ...

  5. Win10如何设置休眠选项(关于睡眠、休眠、快速启动这几个伪关机功能如何设置更适合笔记本电脑?)

    · Win10如何设置休眠选项(关于睡眠.休眠.快速启动这几个伪关机功能如何设置更适合笔记本电脑?) 应用场景 升级正式版win10以后,发现竟然没有休眠选项,从电源管理器里面也没有找到,有时候有些重 ...

  6. springboot里面的缓存注解

    https://blog.csdn.net/u012240455/article/details/80844361 https://lfvepclr.gitbooks.io/spring-framew ...

  7. vue制作滚动条幅-跑马灯效果实例代码

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  8. RYU安装教程

    一.使用pip的形式安装RYU 1.首先检查ubuntu中是否存在pip,命令为 sudo pip3 --version 2.如果存在则使用默认版本8.1.1就行不必跟新,否则自己下载一个pip 3. ...

  9. Python实现DBSCAN聚类算法(简单样例测试)

    发现高密度的核心样品并从中膨胀团簇. Python代码如下: # -*- coding: utf-8 -*- """ Demo of DBSCAN clustering ...

  10. BandwagonHost VPS CentOS7系统启用EPEL源

    BandwagonHost默认安装好了EPEL源,只是默认没有启用,所以很多软件都无法安装.我们需要手动启用一下,才能安装里面的软件. # vim /etc/yum.repos.d/epel.repo ...