题目背景

影魔,奈文摩尔,据说有着一个诗人的灵魂。事实上,他吞噬的诗人灵魂早已成千上万。
千百年来,他收集了各式各样的灵魂,包括诗人、牧师、帝王、乞丐、奴隶、罪人,当然,还有英雄。
每一个灵魂,都有着自己的战斗力,而影魔,靠这些战斗力提升自己的攻击。


题目传送门(内部题42)


输入格式

第一行两个数$n,m$。
第二行$n$个数,第$i$个数即第$i$个灵魂结点的灵魂种类$c_i$。
第三行$n-1$个数,第$i$个数表示$i+1$号灵魂结点的父亲结点。
接下来$m$行,每行两个数$u,d$,表示一组询问。


输出格式

一共$m$行,每一行一个数表示对应询问的答案。


样例

样例输入:

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

样例输出:

1
3
3
1
2


数据范围与提示

对于$30\%$的数据,$n,m\leqslant 1,000$
对于另外$10\%$的数据,保证数据随机
对于另外$20\%$的数据,每次询问满足$d={10}^9$
对于另外$20\%$的数据,满足$n,m\leqslant 20,000$
对于$100\%$的数据,满足$n,m\leqslant 100,000,c_i,n\leqslant n$


题解

我好像又没打正解……

我的思路就是,现将问题离线,然后$DFS$,每次合并儿子的,用线段树合并实现,用树状数组优化。

听着简单,但是实现起来还是蛮难的,调了好久……

不知道有什么好说的了,精髓还是在代码里。

时间复杂度:$\Theta(n\log n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[100000];
int head[100001],cnt;
int n,m;
int c[100001],f[100001];
int trs[400001],depth[100001];
int ans[100001];
vector<pair<int,int> > question[100001];
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
int lowbit(int x){return x&-x;}
void change(int x,int w){for(int i=x;i<=n;i+=lowbit(i))trs[i]+=w;}
int ask(int x){int res=0;for(int i=x;i;i-=lowbit(i))res+=trs[i];return res;}
int tr[4000001],ls[4000001],rs[4000001];
int root[200001],tot;
void insert(int &x,int k,int fl,int l,int r)
{
if(!x)x=++tot;
if(l==r){tr[x]=fl;change(fl,1);return;}
int mid=(l+r)>>1;
if(k<=mid)insert(ls[x],k,fl,l,mid);
else insert(rs[x],k,fl,mid+1,r);
}
void merge(int &x,int fl,int l,int r)
{
if(!fl)return;
if(!x)
{
x=fl;
return;
}
if(l==r)
{
change(max(tr[x],tr[fl]),-1);
tr[x]=min(tr[x],tr[fl]);
return;
}
int mid=(l+r)>>1;
merge(ls[x],ls[fl],l,mid);
merge(rs[x],rs[fl],mid+1,r);
}
void dfs(int x)
{
for(int i=0;i<question[x].size();i++)
ans[question[x][i].first]-=ask(min(depth[x]+question[x][i].second,n))-ask(depth[x]-1);
insert(root[x],c[x],depth[x],0,n);
for(int i=head[x];i;i=e[i].nxt)
{
depth[e[i].to]=depth[x]+1;
dfs(e[i].to);
merge(root[x],root[e[i].to],0,n);
}
for(int i=0;i<question[x].size();i++)
ans[question[x][i].first]+=ask(min(depth[x]+question[x][i].second,n))-ask(depth[x]-1);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
for(int i=2;i<=n;i++)
{
scanf("%d",&f[i]);
add(f[i],i);
}
for(int i=1;i<=m;i++)
{
int u,d;
scanf("%d%d",&u,&d);
question[u].push_back(make_pair(i,d));
}
depth[1]=1;
dfs(1);
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}

rp++

[CSP-S模拟测试]:影魔(树状数组+线段树合并)的更多相关文章

  1. 洛谷P2414 阿狸的打字机 [NOI2011] AC自动机+树状数组/线段树

    正解:AC自动机+树状数组/线段树 解题报告: 传送门! 这道题,首先想到暴力思路还是不难的,首先看到y有那么多个,菜鸡如我还不怎么会可持久化之类的,那就直接排个序什么的然后按顺序做就好,这样听说有7 ...

  2. 树状数组 && 线段树应用 -- 求逆序数

    参考:算法学习(二)——树状数组求逆序数 .线段树或树状数组求逆序数(附例题) 应用树状数组 || 线段树求逆序数是一种很巧妙的技巧,这个技巧的关键在于如何把原来单纯的求区间和操作转换为 求小于等于a ...

  3. hdu1394(枚举/树状数组/线段树单点更新&区间求和)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 ...

  4. hdu 1166:敌兵布阵(树状数组 / 线段树,入门练习题)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submis ...

  5. hdu 5147 Sequence II【树状数组/线段树】

    Sequence IITime Limit: 5000/2500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Problem ...

  6. Color the ball(树状数组+线段树+二分)

    Color the ball Time Limit : 9000/3000ms (Java/Other)   Memory Limit : 32768/32768K (Java/Other) Tota ...

  7. 【poj2182】【poj2828】树状数组/线段树经典模型:逆序查找-空位插入法

    poj2182题意:有一个1~n的排列,现在给定每个人前面有多少个人的编号比他大,求这个排列是什么.n<=8000 poj2182题解: 逆序做,可以确定二分最后一个是什么,然后删除这个数.树状 ...

  8. 【bzoj4785】[Zjoi2017]树状数组 线段树套线段树

    题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作 ...

  9. hdu 1166 敌兵布阵——(区间和)树状数组/线段树

    pid=1166">here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T.表示有T组数据. 每组数据第一 ...

随机推荐

  1. [CSP-S模拟测试]:蔬菜(二维莫队)

    题目描述 小$C$在家中开垦了一块菜地,可以抽象成一个$r\times c$大小的矩形区域,菜地的每个位置都种着一种蔬菜.秋天到了,小$C$家的菜地丰收了. 小$C$拟定了$q$种采摘蔬菜的计划,计划 ...

  2. mysql启动以及常用命令汇总

    mysql57的启动 常用命令 : show databases        :            展示所有数据库 use  数据库名      :     连接数据库 show tables ...

  3. 2018-2019-2 实验三 敏捷开发与XP实践

    实验内容 1.XP基础 2.XP核心实践 3.相关工具 实验要求 1.没有Linux基础的同学建议先学习<Linux基础入门(新版)><Vim编辑器> 课程 2.完成实验.撰写 ...

  4. Mac os下设置国内镜像加速站

    无法忍受国外pip 仓库的龟速地址,安利一波国内高速镜像地址... 首推阿里云 repository 马爸爸  I ❤ u $ vim ~/.pip/pip.conf 在config中做如下配置: [ ...

  5. java并发编程笔记(七)——线程池

    java并发编程笔记(七)--线程池 new Thread弊端 每次new Thread新建对象,性能差 线程缺乏统一管理,可能无限制的新建线程,相互竞争,有可能占用过多系统资源导致死机或者OOM 缺 ...

  6. Oralce-PL/SQL编程-游标

    PL/SQL(Procedural Language/SQL)是Oracle在数据库中引入的一种过程化编程语言. PL/SQL块结构 声明部分 执行部分(必须的) 异常处理部分 [declare] - ...

  7. 最长回文子串 —— Manacher (马拉车) 算法

    最长回文子串 回文串就是原串和反转字符串相同的字符串.比如 aba,acca.前一个是奇数长度的回文串,后一个是偶数长度的回文串. 最长回文子串就是一个字符串的所有子串中,是回文串且长度最长的子串. ...

  8. 【翻译】Knowledge-Aware Natural Language Understanding(摘要及目录)

    翻译Pradeep Dasigi的一篇长文 Knowledge-Aware Natural Language Understanding 基于知识感知的自然语言理解 摘要 Natural Langua ...

  9. 正则split的使用

    import re #\s 空格 +号表示至少出现一次 # path = 'C:\\Users\\cz\Desktop\py06\\PY6_Day01\\爬虫作业\\2018_03_07\\05_sp ...

  10. qt 如何使用 lamda 表达式接收线程中发射的数据,并在里面更新 UI ?

    Qt 信号和槽连接方式 常量 描述 Qt::AutoConnection (默认)如果接收方位于发出信号的线程中,则使用Qt::DirectConnection.否则,使用Qt::QueuedConn ...