CCPC河南省赛-C|树状数组dfs序上处理子树问题 + 离散化

C题地址:大小接近的点对

分析题目:

方法一:

在dfs序上,树状数组维护每个数出现的次数;因为在dfs序上根比它的子孙先遍历到(遍历到根时,还没加入遍历孩子)
题目要统计 u是v的祖先时,dfs序就保证了,"在遍历到的结点x是根,而接下来遍历的都是它的子孙",
递归思想,叶节点先计算完,再向父亲更新,父亲再像父亲更新贡献,完事。

总结:dfs序用来处理 根和它子树问题

很清楚的思想:dfs序上作两次查询,1次统计遍历子树前,1次统计遍历子树后的贡献,两者相减就是子树的贡献了

方法二:主席树在dfs序的 入时间戳 和 出时间戳上 统计区间和,思路没问题吧。

这里先放上方法一的做法,方法二写的代码wa了,但它肯定有被ac的那一天!

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 1e5+10;
ll a[maxn];
ll sum[maxn],c[maxn];
const int INF = 0x3f3f3f3f;
vector<int> vec;
vector<ll> g[maxn];
int  n;
ll k;

//树状数组
int lowbit(int x){
    return x & -x;
}

void add(int x, int v){
    while (x < maxn){
        c[x] += v;
        x += lowbit(x);
    }
}

int query(int x){
    if (x >= maxn)
        return 0;
    int res = 0;
    while (x)
        res += c[x], x -= lowbit(x);
    return res;
}

int rangeQuery(int l, int r){
    return query(r) - query(l - 1);
}

//dfs序上 查询和更新树状数组
void dfs(int x){
    int l = lower_bound(vec.begin(),vec.end(),a[x] - k ) - vec.begin(); //找到左边界下标()
    int r = lower_bound(vec.begin(),vec.end(),a[x] + k ) - vec.begin(); //找到右边界下标()
    if(r >= vec.size() || vec[r] > a[x] + k) --r; //右边界没找到 规定为vec容器的最后一个值
    ll cnt1 = rangeQuery(l,r); //先求出 dfs子树前的贡献
    add(lower_bound(vec.begin(),vec.end(),a[x]) - vec.begin(),1); //出现次数+1
    for(int v : g[x]){
        dfs(v);
        sum[x] += sum[v]; //加上孩子们的贡献
    }
    ll cnt2 = rangeQuery(l,r); //再求出 dfs子树后的贡献
    sum[x] += cnt2 - cnt1; //两者相减的差 就是子树的贡献了
}

int main(){
    scanf("%d %lld",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        vec.push_back(a[i]);
    }
    //离散化
    vec.push_back(-INF);
    sort(vec.begin(),vec.end());
    vec.erase(unique(vec.begin(),vec.end()),vec.end());
    for(int i=1;i<=n-1;i++){
        ll fa;
        scanf("%lld",&fa);
        g[fa].push_back(i+1);
    }
    dfs(1);
    for(int i=1;i<=n;i++) printf("%lld\n",sum[i]);
    return 0;
} 

原文地址:https://www.cnblogs.com/fisherss/p/12233162.html

时间: 2024-11-07 10:56:57

CCPC河南省赛-C|树状数组dfs序上处理子树问题 + 离散化的相关文章

【BZOJ】2434: [Noi2011]阿狸的打字机 AC自动机+树状数组+DFS序

[题意]阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后). l 按一下印有'B'的按键,打字机凹槽中最后一个字母会消失. l 按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失. 我们把纸上打印出来的字符串从1开始顺序编号,一直到n.打字机有一个非

UCF Local Programming Contest 2018 E题(树状数组+dfs序)

如果这道题没有一个限制,那么就是一道树状数组+dfs序的裸题 第一个请求或许会带来困惑,导致想要动态建树,如果真的动态修改树,那么dfs序必定会改变,很难维护,并且数据很大,暴力应该会T 所以不妨先把全部的节点建好,这样只需要求一次dfs序,而对于第一种操作 我们只需要再那个位置减去在他之前的dfs序的bouns求和,并在这个的后一个位置+回来,这样就有这个点被修改,并且成为了一个新点,等同于要求的操作 #include<iostream> #include<cstdio> #in

luogu SP8093 后缀自动机+树状数组+dfs序

这题解法很多,简单说几个: 1. 线段树合并,时间复杂度是 $O(nlog^2n)$ 的. 2. 暴力跳 $fail,$ 时间复杂度 $O(n\sqrt n),$ 比较暴力. 3. 建立后缀树后在 $dfs$ 序上数点,时间复杂度为 $O(nlogn),$ 十分优秀. Code: #include <bits/stdc++.h> #define N 200007 #define setIO(s) freopen(s".in","r",stdin) , f

BZOJ2434 NOI2011 阿狸的打字机 AC自动机+树状数组+DFS序

题意:给定三个操作:1.在当前字符串的末尾添加一个字符c  2.在当前字符串的末尾删除一个字符  3.记录当前字符串并对其标号.再给出N组询问,每组询问需回答第x个字符串在第y个字符串中出现的次数 题解: 首先按照如下规则建Trie,设当前节点为t,第i个字符串的结尾在Trie中的位置为mark[i]: 1.插入操作:看t是否有c这个儿子,有则t=t->child[c],否则t->child[c]=NewNode,t=t->child[c] 2.删除操作:t=t->father 3

HDU5293(SummerTrainingDay13-B Tree DP + 树状数组 + dfs序)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1798    Accepted Submission(s): 585 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n.The

BZOJ 2434: [Noi2011]阿狸的打字机 [AC自动机 Fail树 树状数组 DFS序]

2434: [Noi2011]阿狸的打字机 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2545  Solved: 1419[Submit][Status][Discuss] Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的:l 输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最

[BZOJ 2434][Noi2011]阿狸的打字机(AC自动机+树状数组+dfs序)

Description 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: ·输入小写字母,打字机的一个凹槽中会加入这个字母(这个字母加在凹槽的最后). ·按一下印有'B'的按键,打字机凹槽中最后一个字母会消失. ·按一下印有'P'的按键,打字机会在纸上打印出凹槽中现有的所有字母并换行,但凹槽中的字母不会消失. 例如,阿狸输入aPaPBbP,纸上被打印的字符如下: a aa ab 我们把纸上打印出来的字符串从1开始顺序编号,一直到

【BZOJ-1103】大都市meg 树状数组 + DFS序

1103: [POI2007]大都市meg Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2009  Solved: 1056[Submit][Status][Discuss] Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n的n个小村庄,某些村庄之间有一些双向的土路.从每个村庄都恰好有一条路径到

【BZOJ3653】谈笑风生 离线+树状数组+DFS序

[BZOJ3653]谈笑风生 Description 设T 为一棵有根树,我们做如下的定义: ? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道高明到哪里去了”. ? 设a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数x,那么称“a 与b 谈笑风生”. 给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点.你需要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足: 1. a.b和 c为 T