树状数组入门

用office做了一张pdf - -

这是一维的情形,如果是二维,可以把每一行的一维树状数组看成一个节点,然后再把二维树状数组看成一维树状数组。

好文章:https://www.topcoder.com/community/data-science/data-science-tutorials/binary-indexed-trees/#prob

两道入门题:http://acm.hdu.edu.cn/showproblem.php?pid=1556

http://poj.org/problem?id=2155

对于第一题HDU1556:

题意:初始数组元素值都为0,给定区间[x,y],将区间[x,y]每个元素的值+1,最后输出整个数组每个元素的值。

更新区间[x,y]的话,可以只更新两个点x,y+1(将所有管辖x的区间+1,所有管辖y+1的区间-1)

查询点p,将p管辖的区间的值加起来就行了。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

int a[100005],N;

int lowbit(int x)
{
    return x&(-x);
}

void update(int x,int v)
{
    while(x && x<=N)
    {
        a[x]+=v;
        x+=lowbit(x);
    }
}

int query(int x)
{
    int ret=0;
    while(x>0)
    {
        ret+=a[x];
        x-=lowbit(x);
    }
    return ret;
}

int main()
{
    int i,j,x,y;
    while(scanf("%d",&N),N)
    {
        memset(a,0,sizeof(a[0])*(N+2));
        for(i=1;i<=N;i++)
        {
            scanf("%d%d",&x,&y);
            update(x,1);
            update(y+1,-1);
        }
        for(i=1;i<N;i++)
            printf("%d ",query(i));
        printf("%d\n",query(N));
    }
    return 0;
}

这题不是边更新边查询,所以可以用更简单的方法做。由于是更新完再查询,可以在每次更新的时候将两个端点标记一下,左后再统一更新一遍就行了。

代码:

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

int s[100005]; 

int main()
{
    int n,x,y,i;
    while(scanf("%d",&n),n)
    {
        memset(s,0,sizeof(s));
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&x,&y);
            s[x-1]--;
            s[y]++;
        }
        for(i=n-1;i>=1;i--)
            s[i]+=s[i+1];
        for(i=1;i<n;i++)
            printf("%d ",s[i]);
        printf("%d\n",s[n]);
    }
    return 0;
}

对于第二题POJ2155:

题意:给定一个N*N的矩阵,矩阵上每个元素的初始值为0,有两种操作①给出一个子矩阵(左上角和右下角的坐标),将子矩阵的每个元素的值取反②查询一个元素的值

由于每次查询的答案只有0和1,可以统计每个元素被修改过多少次,如果为奇数次那么答案为1,否则为0。修改和查询几乎和上面那题一样,只是多了一维。

代码:

#include <iostream>
#include <cstdio>

using namespace std;

int N,a[1006][1006];

void Clear()
{
	for(int i=0;i<=N+1;i++)
		for(int j=0;j<=N+1;j++)
			a[i][j]=0;
}

int lowbit(int x)
{
	return x&(-x);
}

void update(int x,int y,int v)
{
	for(int i=x;i<=N;i+=lowbit(i))
		for(int j=y;j<=N;j+=lowbit(j))
			a[i][j]+=v;
}

int query(int x,int y)
{
	int ret=0;
	for(int i=x;i>0;i-=lowbit(i))
		for(int j=y;j>0;j-=lowbit(j))
			ret+=a[i][j];
	return ret;
}

int main()
{
	int ncase,q,x1,x2,y1,y2;
	char str[2];
	scanf("%d",&ncase);
	for(int i=1;i<=ncase;i++)
	{
		scanf("%d%d",&N,&q);
		Clear();
		while(q--)
		{
			scanf("%s",str);
			if(str[0]=='C')
			{
				scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
				update(x1,y1,1);
				update(x2+1,y1,-1);
				update(x1,y2+1,-1);
				update(x2+1,y2+1,1);
			}
			else
			{
				scanf("%d%d",&x1,&y1);
				printf("%d\n",query(x1,y1)%2);
			}
		}
		printf("\n");
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-12 08:38:06

树状数组入门的相关文章

HDU 1166 敌兵布阵【树状数组入门题】

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

Binary Indexted Tree 树状数组入门

感谢http://www.cnblogs.com/xudong-bupt/p/3484080.html 树状数组(BIT)是能够完成下述操作的数据结构: 给定一初始值全为零的数列a1,a2a,a3...,an 1.给定i,计算a1+a2+...+ai 2.给定i和x,执行ai+=x BIT的结构: 数组bit[N] bit[1]=C1=A1;bit[2]=C2=C1+A2; BIT就是使用数组来维护上面所说的部分和 以1结尾的1,3,5,7长度为1 以1个0结尾的2,6长度为2 以两个0结尾的4

HDU 1166 敌兵布阵 (树状数组入门)

树状数组的引入: 对于查询和修改要求差不多,使用树状数组可以达到logN的复杂度 红色矩形表示的数组C就是树状数组.这里,C[i]表示A[i-2^k+1]到A[i]的和,而k则是i在二进制时末尾0的个数,或者说是i用2的幂方和表示时的最小指数. 所谓的k,也是该节点在树中的高度. 修改第i个元素,为了维护数组C的意义,需要修改C[i]以及C[i]的全部祖先,而非C[i]的祖先的节点则对于第i个元素的修改,不会发生改变.祖先共有"树的高度 - C[i]节点高度"个 要求区间[p,q]元素

poj2299 树状数组入门题

题意:利用树状数组求逆序数: 思路:因为输入范围较大,先离散化一下,得到的数组a记录了原来数组的大小关系:然后按下标顺序执行add(a[i],1),这样sum(a[i])得到的就是小于等于a[i]的个数,i-sum(a[i])即为a[i]前面比a[i]大的数的个数 //外循环n次并累加i-sum(a[i])得到逆序数 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<alg

树状数组入门篇2

树状数组的高效性主要就是通过将一条线段分成若干个小线段(其中每个小线段存储着2^k大小的区间和,这就将区间和问题复杂度降到了logn),而不是一个一个单一的点 add()操作修改了单点的值,同时对之后的父亲节点进行了更新(之所以只更新该点以及该点的父亲节点而不更新该点的非父亲节点,是因为求和时父亲节点直接包含该点所以会跳过该点,也就不能接受该点,所以就需要自身更新,而非父亲节点在求和时会直接加上该点,所以就不需要进行更新) 正是由于add()操作对父亲节点以及非父亲节点的区别才使每次的sum()

HDU-1166 敌兵布阵 (线段树&amp;&amp;树状数组入门)

敌兵布阵 C国的死对头A国这段时间正在进行军事演习,所以C国间谍头子Derek和他手下Tidy又开始忙乎了.A国在海岸线沿直线布置了N个工兵营地,Derek和Tidy的任务就是要监视这些工兵营地的活动情况.由于采取了某种先进的监测手段,所以每个工兵营地的人数C国都掌握的一清二楚,每个工兵营地的人数都有可能发生变动,可能增加或减少若干人手,但这些都逃不过C国的监视. 中央情报局要研究敌人究竟演习什么战术,所以Tidy要随时向Derek汇报某一段连续的工兵营地一共有多少人,例如Derek问:"Tid

二维树状数组入门题 poj2642Stars

题目连接:Stars 题解:把一维的的树状数组扩展到二维就行,复杂度为o(mlog^2n) #include<bits/stdc++.h> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #include<algorithm> #define pb pus

树状数组入门(求和)

Description 输入一个数列A1,A2-.An(1<=N<=100000),在数列上进行M(1<=M<=100000)次操作,操作有以下两种:(1)格式为C I X,其中C为字符"C",I和X(1<=I<=N,|X|<=10000)都是整数,表示把把a[I]改为X(2)格式为Q L R,其中Q为字符"Q",L和R表示询问区间为[L,R](1<=L<=R<=N),表示询问A[L]+-+A[R]的值.

树状数组入门 hdu1541 Stars

树状数组 树状数组(Binary Indexed Tree(B.I.T), Fenwick Tree)是一个查询和修改复杂度都为log(n)的数据结构.主要用于查询任意两位之间的所有元素之和,但是每次只能修改一个元素的值:经过简单修改可以在log(n)的复杂度下进行范围修改,但是这时只能查询其中一个元素的值(如果加入多个辅助数组则可以实现区间修改与区间查询). 树状数组和线段树很像,但能用树状数组解决的问题,基本上都能用线段树解决,而线段树能解决的树状数组不一定能解决.相比较而言,树状数组效率要