树状数组_POJ树状数组初探

本文出自:http://blog.csdn.net/svitter

树状数组用于处理求区间内的值和改变单个元素的值,要注意树状数组从数组下标1开始。

基础算法:

获取全部的lowbit值,防止重复计算。

void getLowbit()
{
    for(int i = 0; i < 1000; i++)
        lowbit[i] = i & (-i);
}

求区间和1~i:

int Sum(int i)
{
    int sum = 0;
    while(i > 0)
    {
        sum += C[i];
        i = i - lowbit[i];
    }
    return sum;
}

改变一个元素i数值:

void Change(int i, int inc)
{
	while(i <= n)
	{
		C[i] += inc;
		i = i + lowbit[i];
	}
}

Cn的求法:

sum(n) - sum(n - lowbit(n));

题目:POJ3321

题意:一颗苹果树,树上有多个苹果,一个分支一个苹果,求一个节点以上苹果的个数。操作有添加和删除苹果。(如果原本有苹果,则添加,没有则删除。一开始全部有苹果)。

测试数据:第一行为一个n,代表分支个数。随后输入分支关系。(邻接表)第二行为一个m,代表操作个数。随后输入Q或者C加一个数字,代表求和或者对树进行删除或者添加操作。

思路:考虑是稀疏图使用邻接表存存储。STL_稀疏图,树_使用vector邻接表存储。求段间和,只改变其中一个元素,可以使用树状数组。以根为1,向上节点为另一边。使用深搜统计苹果数量。

C[i]就是Sum(i) - Sum(i - lowbit[i]) 即为 i - (i - lowbit[i]); C[ time ] ;

Q: 使用start[n]和end[n]来存储访问时间,使用( end[n] - start[n] + 1 )/ 2 求出最后结果(除了选择节点的苹果,其他的苹果都走了两遍)。

C: 更改与树状数组的modify结合,更改apple节点。Query函数求出的不是苹果的值。

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>

using namespace std;

#define MY_MAX 220000

typedef vector<int> VCT_INT;
vector <VCT_INT> G(MY_MAX/2);

int C[MY_MAX];
int lowbit[MY_MAX];

bool HasApple[MY_MAX];

int start[MY_MAX];
int end[MY_MAX];
int nCount = 0;

void DFS(int v)
{
    start[v] = ++ nCount;
    for(int i = 0; i < G[v].size(); i++)
        DFS(G[v][i]);
    end[v] = ++ nCount;
}

int QuerySum(int p)
{
    int nSum = 0;
    while(p > 0)
    {
        nSum += C[p];
        p -= lowbit[p];
    }
    return nSum;
}

void Modify(int p, int val)
{
    while(p <= nCount)
    {
        C[p] += val;
        p += lowbit[p];
    }
}

void getLowbit()
{
    for(int i = 1; i < MY_MAX; i++)
        lowbit[i] = i & (-i);
}

int main()
{
    int n, m;
    scanf("%d", &n);
    int x, y, i, j ,k;
    int a, b;
    getLowbit();
    //build map
    for(i = 0; i < n - 1; i++)
    {
        scanf("%d%d", &a, &b);
        G[a].push_back(b);
    }
    nCount = 0; DFS(1);
    for(i = 1; i <= n; i++)
        HasApple[i] = 1;

    for(i = 1; i <= nCount; i++)
        C[i] = i - (i - lowbit[i]);

    scanf("%d", &m);

    while(m--)
    {
        char cmd[10];
        scanf("%s%d", cmd, &a);
        if(cmd[0]== 'C')
        {    if(HasApple[a])
            {
                Modify(start[a], -1);
                Modify(end[a], -1);
                HasApple[a] = 0;
            }
            else
            {
                Modify(start[a], 1);
                Modify(end[a], 1);
                HasApple[a] = 1;
            }
        }
        else
        {
            int t1 = QuerySum(end[a]);
            int t2 = QuerySum(start[a]-1);
            printf("%d\n", (t1-t2)/2);
        }
    }

    return 0;
}
时间: 2024-10-30 20:53:03

树状数组_POJ树状数组初探的相关文章

【bzoj1146】[CTSC2008]网络管理Network 倍增LCA+dfs序+树状数组+主席树

题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成.每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络.该网络结构保证网络中的任意两个路由器之间都存在一条直接或间接路径以进行通信. 高速光缆的数据传输速度非常快,以至于利用光缆传输的延迟时间可以忽略.但是由于路由器老化,在这些

hdu 1166 树状数组 线段树

敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 51177    Accepted Submission(s): 21427 Problem Description C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成了一个序列,每个妹子有一个美丽度. Bakser神犇与他打算研究一下这个妹子序列,于是Bakser神犇问道:"你知道区间 [l,r]中妹子们美丽度的逆序对数吗?" 蒟蒻Autumn只会离线乱搞啊……但是Bakser神犇说道:"强制在线." 请你帮助一下Autumn吧.

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

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1394 题意:给出一个循环数组,求其逆序对最少为多少: 思路:对于逆序对: 交换两个相邻数,逆序数 +1 或 -1, 交换两个不相邻数 a, b, 逆序数 += 两者间大于 a 的个数 - 两者间小于 a 的个数: 所以只要求出初始时的逆序对数,就可以推出其余情况时的逆序对数.对于求初始逆序对数,这里 n 只有 5e3,可以直接暴力 / 树状数组 / 线段树 / 归并排序: 代码: 1.直接暴力 1

【LuoguP3038/[USACO11DEC]牧草种植Grass Planting】树链剖分+树状数组【树状数组的区间修改与区间查询】

模拟题,可以用树链剖分+线段树维护. 但是学了一个厉害的..树状数组的区间修改与区间查询.. 分割线里面的是转载的: -------------------------------------------------------------------------------- [ 3 ]  上面都不是重点--重点是树状数组的区间修改+区间查询 这个很好玩 其实也挺简单 首先依旧是引入delta数组 delta[i]表示区间 [i, n] 的共同增量 于是修改区间 [l, r] 时修改 delt

js List&lt;Map&gt; 将偏平化的数组转为树状结构并排序

数据格式: [ { "id":"d3e8a9d6-e4c6-4dd8-a94f-07733d3c1b59", "parentId":"6d460008-38f7-479d-b6d1-058ebc17dae3","myorder":1, "name":"任务一" }, { "id":"6d460008-38f7-479d-b6d1-058e

【BZOJ-1452】Count 树状数组 套 树状数组

1452: [JSOI2009]Count Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 1769  Solved: 1059[Submit][Status][Discuss] Description Input Output Sample Input Sample Output 1 2 HINT Source Solution 忽略标题的说法...撞壁用的.... 简单题,裸树状数组套树状数组 颜色数目$c<=100$很小,考虑对于每种颜色单独进