题目

其实 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. [CF662C Binary Table][状压+FWT]

    CF662C Binary Table 一道 FWT 的板子-比较难想就是了 有一个 \(n\) 行 \(m\) 列的表格,每个元素都是 \(0/1\),每次操作可以选择一行或一列,把 \(0/1\) ...

  2. CodeForces - 1107E 区间DP

    和紫书上的Blocks UVA - 10559几乎是同一道题,只不过是得分计算不同 不过看了半天紫书上的题才会的,当时理解不够深刻啊 不过这是一道很好区间DP题 细节看代码 #include<c ...

  3. iPad成为Windows系统的第二屏幕

    一.Windows端软件准备 1.Splashtop Wired XDisplay Agent (官网下载     快速下载​) 2.iTunes (点击此处跳转至微软应用商店) 二.iPad端软件准 ...

  4. C++11智能指针(unique_ptr、shared_ptr、weak_ptr)(转)

    原文地址:https://blog.csdn.net/king_way/article/details/95536938

  5. .NetCore学习笔记:三、基于AspectCore的AOP事务管理

    AOP(面向切面编程),通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑 ...

  6. Excel数据源增加时,渗透表如何刷新?

    使用Excel制作渗透表的时候在选择数据源范围的时候不要选择有限区域!!!最好圈定列范围 问题:制作渗透表是,在选择数据区域时使用[Ctrl + A]或者选定有限的数据区域,从而导致当数据源增加时,渗 ...

  7. [TJOI2013] 攻击装置 - 二分图匹配

    给定 \(N \times N\) 棋盘,某些格子是障碍,问可以放置的互不侵犯的马的个数 黑白染色后建立二分图,求最大独立集 = 总点数 - 最大匹配数 注意把反边也连上会WA掉(脑抽一发血) #in ...

  8. eclipse如何查看源码

    方式一: Source not found The JAR file X:\xxxx\xxxx\xxxx\xx has no source attachment. 没有源附件. You can att ...

  9. 四、CentOS 7安装Oracle JDK

    CentOS 7安装Oracle JDK,查看Linux是否自带的JDK,如有openJDK,则卸载  CentOS7.1 JDK安装 1.卸载自带OPENJDK    用 java -version ...

  10. 巨杉Tech | 使用 SequoiaDB 分布式数据库搭建JIRA流程管理系统

    介绍 JIRA是Atlassian公司出品的项目与事务跟踪工具,被广泛应用于缺陷跟踪.客户服务.需求收集.流程审批.任务跟踪.项目跟踪和敏捷管理等工作领域.很多企业与互联网公司都在使用Jira作为内部 ...