区间内出现某个数k次的数目问题

该博客讨论了如何解决一个关于树的问题,其中每个节点具有权值,目标是找出某个节点及其子节点中权值出现k次的数量。通过将树转换为连续区间并离线处理询问,对区间按右端点排序,使用树状数组来维护区间内出现k次的权值种类。算法的时间复杂度为O((n+q)log(n))。
摘要由CSDN通过智能技术生成

hdu4358

题意是给你一棵树,每个节点都有一个权值,问你某个节点及其子节点中权值出现k次的有多少个。

首先要想到把树转化为连续区间,先读取所有询问进行离线处理。把询问的子树转化成区间,按区间的右端点从小到大排序。然后从左到右循环整个区间每个值。假设当前循环到了第i个位置,这个位置的值为v,维护一个树状数组,树状数组中d位置的值就是区间[d,i]中出现k次的权值的种类,考虑到价值v的维护,记录一个数组show[v][p]表示第p个v值出现的位置,
那么可以想到,从i往前推k个v值的地方和往前推k+1个v值的地方之间的权值种类可以+1,所以整个过程的复杂度在O((n+q)log(n))

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
using namespace std;

#define N 100001
vector <int> show[N], e[N];
map <int, int> M;
int W[N], L[N], R[N];
int cnt, c[N], ans[N];
struct Node
{
    int l, r, id;
    bool operator<(const Node &a)const
    {
        return r<a.r;
    }
}node[N];
void ini()
{
    cnt = 1; M.clear();
    memset(c, 0, sizeof(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值