【Codeforces-208E】Blood Cousins(dsu on tree+离线)

本文介绍了一种基于深度优先搜索和离线查询处理的算法,用于解决在家族关系树中查找特定个体的p代堂兄弟数量的问题。通过构建树结构并进行两次深度遍历,算法能够高效地计算出每个查询的答案。

Polycarpus got hold of a family relationship tree. The tree describes family relationships of n people, numbered 1 through n. Each person in the tree has no more than one parent.

Let’s call person a a 1-ancestor of person b, if a is the parent of b.

Let’s call person a a k-ancestor (k > 1) of person b, if person b has a 1-ancestor, and a is a (k - 1)-ancestor of b’s 1-ancestor.

Family relationships don’t form cycles in the found tree. In other words, there is no person who is his own ancestor, directly or indirectly (that is, who is an x-ancestor for himself, for some x, x > 0).

Let’s call two people x and y (x ≠ y) p-th cousins (p > 0), if there is person z, who is a p-ancestor of x and a p-ancestor of y.

Polycarpus wonders how many counsins and what kinds of them everybody has. He took a piece of paper and wrote m pairs of integers vi, pi. Help him to calculate the number of pi-th cousins that person vi has, for each pair vi, pi.

Input
The first input line contains a single integer n ( 1   ≤   n   ≤   1 0 5 ) n (1 ≤ n ≤ 10^5) n(1n105) — the number of people in the tree. The next line contains n space-separated integers r1, r2, …, rn, where r i ( 1   ≤   r i   ≤   n ) r_i (1 ≤ r_i ≤ n) ri(1rin) is the number of person i’s parent or 0, if person i has no parent. It is guaranteed that family relationships don’t form cycles.

The third line contains a single number m ( 1   ≤   m   ≤   1 0 5 ) m (1 ≤ m ≤ 10^5) m(1m105) — the number of family relationship queries Polycarus has. Next m lines contain pairs of space-separated integers. The i-th line contains numbers v i , p i ( 1   ≤   v i ,   p i   ≤   n ) v_i, p_i (1 ≤ v_i, p_i ≤ n) vi,pi(1vi,pin).

Output
Print m space-separated integers — the answers to Polycarpus’ queries. Print the answers to the queries in the order, in which the queries occur in the input.

Examples
input
6
0 1 1 0 4 4
7
1 1
1 2
2 1
2 2
4 1
5 1
6 1
output
0 0 1 0 0 1 1

这个题感觉挺绕的,就是给出的查询v和p,问的是以v的第p个祖先的这个子树下,有多少个和v一样深度的点。
所以实际上知道v以后,我们只需要知道他的祖先的是哪个点,直观上可以跑个暴力,显然超时,这里就用到了dsu on tree了,那么我们还需要知道附着在某个子树下的查询有多少个,开个vector就行了。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<set>
#define ll long long
#define maxx 100005
#define INF 0x7f7f7f7f
using namespace std;
int n,m;
int head[maxx],to[maxx],_next[maxx];
int edge;
void addEdge(int x,int y)
{
    to[++edge]=y,_next[edge]=head[x],head[x]=edge;
}
vector<pair<int ,int> >q[maxx];
vector<pair<int ,int> >_q[maxx];
int son[maxx];
int deep[maxx];
int _size[maxx];
int a[maxx],cnt;
void dfs1(int u)
{
    a[++cnt]=u;
    for(int i=0;i<q[u].size();i++)
    {
        if(q[u][i].first>=cnt)_q[0].push_back(q[u][i]);
        else _q[a[cnt-q[u][i].first]].push_back(q[u][i]);//附着到某个子树的查询
    }
    _size[u]=1;
    int maxson=-1;
    for(int i=head[u];i;i=_next[i])
    {
        int v=to[i];
        deep[v]=deep[u]+1;
        dfs1(v);
        cnt--;
        _size[u]+=_size[v];
        if(maxson<_size[v])
        {
            son[u]=v;
            maxson=_size[v];
        }
    }
}
int l[maxx],r[maxx],_index;
int b[maxx];
void dfs2(int u)
{
    l[u]=++_index;
    b[_index]=deep[u];
    for(int i=head[u];i;i=_next[i])
    {
        int v=to[i];
        dfs2(v);
    }r[u]=_index;
}
int ans[maxx];
int tot[maxx];
inline void del(int u)
{
    for(int i=l[u];i<=r[u];i++)tot[b[i]]=0;
}
inline void add(int u)
{
    for(int i=l[u];i<=r[u];i++)tot[b[i]]++;
}
void dfs(int u)
{
    for(int i=head[u];i;i=_next[i])
    {
        int v=to[i];
        if(v==son[u])continue;
        dfs(v);
        del(v);
    }
    if(son[u])
    {
        dfs(son[u]);
        for(int i=head[u];i;i=_next[i])
        {
            int v=to[i];
            if(v!=son[u])add(v);
        }
    }
    if(u)
    {
        for(int i=0;i<_q[u].size();i++)
            ans[_q[u][i].second]=tot[deep[u]+_q[u][i].first]-1;
    }
    else for(int i=0;i<_q[u].size();i++)
            ans[_q[u][i].second]=0;
    tot[deep[u]]++;
}
int main()
{
    cin>>n;
    int x,y;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&x);
        addEdge(x,i);
    }
    cin>>m;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&x,&y);
        q[x].push_back(make_pair(y,i));
    }
    dfs1(0);
    dfs2(0);
    dfs(0);
    for(int i=1;i<m;i++)
        printf("%d ",ans[i]);
    printf("%d\n",ans[m]);
    return 0;
}

内容概要:本文介绍了一套针对智能穿戴设备的跑步/骑行轨迹记录系统实战方案,旨在解决传统运动APP存在的定位漂移、数据断层和路径分析单一等问题。系统基于北斗+GPS双模定位、惯性测量单元(IMU)和海拔传感器,实现高精度轨迹采集,并通过卡尔曼滤波算法修正定位误差,在信号弱环境下利用惯性导航补位,确保轨迹连续性。系统支持跑步与骑行两种场景的差异化功能,包括实时轨迹记录、多维度路径分析(如配速、坡度、能耗)、数据可视化(地图标注、曲线图、3D回放)、异常提醒及智能优化建议,并可通过蓝牙/Wi-Fi同步数据至手机APP,支持社交分享与专业软件导出。技术架构涵盖硬件层、设备端与手机端软件层以及云端数据存储,强调低功耗设计与用户体验优化。经过实测验证,系统在定位精度、续航能力和场景识别准确率方面均达到预期指标,具备良好的实用性和扩展性。; 适合人群:具备一定嵌入式开发或移动应用开发经验,熟悉物联网、传感器融合与数据可视化的技术人员,尤其是从事智能穿戴设备、运动健康类产品研发的工程师和产品经理;也适合高校相关专业学生作为项目实践参考。; 使用场景及目标:① 开发高精度运动轨迹记录功能,解决GPS漂移与断点问题;② 实现跑步与骑行场景下的差异化数据分析与个性化反馈;③ 构建完整的“终端采集-手机展示-云端存储”系统闭环,支持社交互动与商业拓展;④ 掌握低功耗优化、多源数据融合、动态功耗调节等关键技术在穿戴设备中的落地应用。; 阅读建议:此资源以真实项目为导向,不仅提供详细的技术实现路径,还包含硬件选型、测试验证与商业扩展思路,建议读者结合自身开发环境,逐步实现各模块功能,重点关注定位优化算法、功耗控制策略与跨平台数据同步机制的设计与调优。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值