看博客的日常

来源:互联网 发布:各编程语言比较 编辑:程序博客网 时间:2024/05/17 03:41

很久没写了,传一篇看树状数组博客的分析,算是日常,过两天将线段树和树状数组一起总结一下。内容如下


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!树状数组处理数据时,一定要注意边界是否有0,最好每个数据自加一次!!!!!!!!!!!

 

 

树状数组总结

1核心代码

更新数组数据

void add(int x,int v){//x!=0

While(x<=max){

a[x]+=v;

x+=lowbit(x);//x+=x&-x;

}

}

求和

int sum(int x){

int ans=0;

While(x>0){

ans+=a[x];

x-=lowbit(x);

}

return ans;

}

基本目的,对于一个数组,可以对各个数组的数据进行更新或者求前i组的和,若仅仅按照题意进行更改的话,时间复杂度将为On*m,而如果使用树状数组的话,时间复杂度直接变为O(m*lgn)

关于为何会减小复杂度,见下博客

传送门:http://blog.csdn.net/int64ago/article/details/7429868

其他的简单变形

单点数据更新,求关于区间的数据

UVA1428 Ping pong(树状数组)

http://blog.csdn.net/u013480600/article/details/20912063

树状数组可用于寻找比a[i]小的数的个数(如此说不算准确,详见题目)

Memset(c,0,sizeof(c));

ans=sum(a[i]);

add(a[i],1);

*tips:数组c[i]树状,既可更新维护单个数据,又可求和

2,求逆序数

a1,a2,a3......................an i=1...........n

逆序数为

ans=0;

for(i=1................n){

ans+=i-sum(a[i]);//sum(a[i])所求的是数列中比a[i]小的数的个数,i-sum(),得到的就是前i

//个数中比a[i]大的,也即逆序数

}

 

 

POJ 3378 Crazy Thairs(数据集中+DP+树状数组+高精度)

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

////二维树状数组初探

Tips:

1,离散化

http://blog.csdn.net/gokou_ruri/article/details/7723378

有些数据本身很大,自身无法作为数组的下标保存对应的属性。

如果这时只是需要这堆数据的相对属性,那么可以对其进行离散化处理!

离散化:当数据只与它们之间的相对大小有关,而与具体是多少无关时,可以进行离散化。

Etc://此例子改变了各组数的大小,但关系未变,数目未变;另一种离散化需要删除重复元素

node类中,node.v存数值,node.index记录node数组中的下标,当v中的值极大时,无法存储,但其精确数值与本题无关,我们只需了解数组中不同位置的大小关系,由此,按如下代码进行离散化

1. sort(nodes+1,nodes+n+1);  

2.         int max_num=0;//表示当前重新映射后的最大值  

3.         a[nodes[1].index]=++max_num;  

4.         for(int i=2;i<=n;i++)  

5.         {  

6.             if(nodes[i].v==nodes[i-1].v) a[nodes[i].index]=max_num;  

7.             else a[nodes[i].index]=++max_num;  

8.         }  

 

2,高精度化

当数据极大,超过long long时,用数组来存储大数据,a[0]存储位数,运算工具,原理不难,详见http://wenku.baidu.com/link?url=F3Jr5ly5vZ7NZhgA-VM9yA6E1EnDtxqc-0YmoHKvI4CmiLhSC4wRVa3iaupDLjKbe3AdvDbboIv79J0CzM53Rnh3AgSFheRCxvOqyy25cbS

PS:有空上网搜搜模板(滑稽)

此题为啥要用高精度?因为极端情况,若有5000个数,每个都不同,则结果有C(5,5000)>2^64>long long

HDU 3450 Counting Sequences(树状数组+DP+离散化)///这题要再看两遍,有玄机

http://acm.hdu.edu.cn/showproblem.php?pid=3450

///二维树状数组再探

注意二分

问题:1为啥一定要对9901取膜?

2temp=(temp+MOD)%MOD;////why

HDU 3743 Frosh Week(树状数组或归并排序求逆序)

http://acm.hdu.edu.cn/showproblem.php?pid=3743

呃,离散加树状数组,没啥可说的。重点在于逆序数的使用

HDU 2838 Cow Sorting(树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=2838

简单的单点数据更新,一个数组记录逆序数,另一个数组记录cost

注意结果用long long

POJ 2182 Lost Cows(树状数组,暴力解法)

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

这个二分法很强,要揣摩揣摩

POJ 1990 MooFest(树状数组+离线处理)

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

每个node中,一个存音量,一个存坐标。因为普通做法On^2)超时。用树状数组优化,我们先将数组按音量大小排序,这样新数列中,只要管左边的就行。ans+=(坐标比i大的与i的距离+坐标比i小的与i的距离)*v[i]。此时,开两个树状数组,aba存新数列中比i坐标小的个数,b存新数列中比i坐标小的坐标和。这样,小的距离和m=a*x[i]-b;大的距离和n=total(此为新数列中前i个的坐标总值)-b-a*x[i];从而求出结果。

区间数据更新,求关于单点的(更改次数等)

HDU 1556 Color the ball(树状数组)

http://acm.hdu.edu.cn/showproblem.php?pid=1556

据说线段树做更简单。学完试试。对ab间的数据更新,add(a,1);add(b+1,-1);这样就满足题意。结果用sum(i)输出(傻了傻了,想这题时忘了树状数组性质c[i]存储的是前i组的和)。

add(b+1,-1)使得可以进行单点查询。这篇博客中是向上更新,向下统计。其他的很多都是相反的,不知是否只是便于理解才如此。先看看其他区间更新的

 

Left,单点更新,删除元素

哈希表的预处理,使得时间复杂度变为O(1),有点像链表,但比链表好查找数据,有空看。。。。

http://blog.csdn.net/u013480600/article/details/21547113

 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////饶齐//////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////////////////////

第二篇博客

http://blog.csdn.net/u012860063/article/details/24810563

关于向上(下)更新,向下(上)统计,先自己理解。这篇不错

///////////////////////////////////////////////////////////

Re0;

树状数组最基本的用法,单点数据更新,求区域和。此时,(目前为止)全部都是向上更新,向下统计

延伸用途1

逆序数的应用,对于一列数,计算这个数列中数之间的大小关系(与数据的位置有关)。也算是单点数据更新,因为用树状数组每存(更新)一次数据,计算一次

Etc:

HDU2492 Ping pong 树状数组求逆序数

续逆序数:

poj3067 Japan

先要明白要求的公式(x1-x2)*(y1-y2)<=0,这样,我们就能对数对先按一个数据排序,再求另一组数据的逆序数

逆序数变形

Codeforces Round #261 (Div. 2) D. Pashmak and Parmida's problem

这题是什么鬼。。。。。。。。。。。。。。。。。。。

CSU 1335: 高桥和低桥

区域数据更新,统计单点数据。

为啥要二分?傻了。。。。。。105*105*25必然。。。

的确,向下更新,向上统计好理解,另一种也可以,但难理解

/////////////////////////////////////////////////////////////////////////////////

为啥要对数据离散化

http://blog.csdn.net/u012860063/article/details/45460933

这篇博客讲的很好。对于树状数组,更新数据时,其存储很像位存储,不离散化,浪费空间。同时,由于树状数组的特性,使用时常有大数,所以二分求值也是必要的。

多用long long

 

HDU 4217 Data Structure?

单点数据更新,自认为这题挺不错,树状数组应用的典型。

模拟的话,时间复杂度为O(n^2),所以要用树状数组优化。这里更新原数组数据有特定条件,因此运用二分。

拓展:如果本题要删除一个无序数组中的第ki个元素,则树状数组在开始读入数据时,要add(i,a[i].v)或add(a[i].index,a[i].v),之后在删除时,进行add(a[i].index,-a[i].v)。定义index存储原本位置,之后找第ki个元素时排序。要访问第index个元素,使用sum(a[i].index)-sum(a[i].index-1)。PS:又想了想,要定义二维树状数组,c[1][]处理按大小排列后的数组的下标。要删除原数列元素,就要按上面说的,用第二维操作。

//////////////////////////////////////////////////////////////////////////////////////////////////////tianyiming////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////

第三篇博客。。。。

http://blog.csdn.net/wmn_wmn/article/category/896475/1

hdu2642 Stars

另一种二维树状数组。。。。。基本的,据说算裸二维。。。。不难,简单的单点更新,区间查询。新技能get,对面上的点的做法。。

 

NYOJ 522 裸的树状数组

不想翻译。。。。。。。博主说是水题,那就(滑稽)。。

 

Enemy is weak 树状数组

求逆序数加离散化。。。。。其实就是pingpang那个题的变形,不对,一样,就是题干换了,但注意要对数据离散化,以及边界不为0。

 

POJ 3321 Apple Tree 

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

Dfs+树状数组。好题!!用链表存储树上的数据。单点更新,区间查询。难点是将如何将各个子树上的数值统计。可以用dfs遍历,还有,要用一个数组记录节点的状态

1. void dfs(int x){  

2.     down[x] = order;//down[]记录靠近根节点的数值  

3.     for(int i = head[x]; i != -1; i = ee[i].next){  

4.        int y = ee[i].rp;  

5.        dfs(y);  

6.     }  

7.     up[x] = order++;  //每遍历一层加一

8. }  

上面算是预处理。之后就是套路,将数值存到树状数组中就好,更新时,add(up[i],1);或add(up[i],-1);对节点值取反。

求和sum(up[i])-sum(down[i]-1)

 

POJ 1195 Mobile phones 

裸的二维数组

star那道题一样,二维数组模板

1. void update(int x,int y,int add){  

2.     int t = y;  

3.     while(x < N){  

4.        y = t;  

5.        while(y < N){  

6.          num[x][y] += add;  

7.          if(num[x][y] < 0)  

8.              num[x][y] = 0;  

9.          y += lowbit(y);  

10.        }  

11.        x += lowbit(x);  

12.     }  

13. }  

14. LL sum(int x,int y){  

15.     int t = y;  

16.     LL s = 0;  

17.     while(x > 0){  

18.        y = t;  

19.        while(y > 0){  

20.          s += num[x][y];  

21.          y -= lowbit(y);  

22.        }  

23.        x -= lowbit(x);  

24.     }  

25.     return s;  

26. }  

在图像中逐行更新

 

HDU 3584 Cube 

裸的三维树状数组

1.    update(x2,y2,z2,1);  

2.             update(x1-1,y2,z2,-1);  

3.             update(x2,y1-1,z2,-1);  

4.             update(x2,y2,z1-1,-1);  

5.             update(x1-1,y1-1,z2,1);  

6.             update(x1-1,y2,z1-1,1);  

7.             update(x2,y1-1,z1-1,1);  

8.             update(x1-1,y1-1,z1-1,-1);  

这个更新。。。。。不明白

明天看题意,应该不难。。。。

区间更新,单点查询。向下更新,向上查询

POJ 2029 Get Many Persimmon Trees 

同样没找到题意。。。。。。

裸的二维树状数组。。。单点更新,区间查询

 

HDU 3015 Disharmony Trees

1990那道题一样,挺有意思的,将最大值改为最小值,更改排序顺序即可,刚看完就有点忘。。。。。

单点更新,区间查询。开俩数组,一个记录原数组下标,一个记录原数组数值。(看完资料写一遍!)PS:博主对原数组排了两边序。。。自己写时看看,感觉一个就可以

 

 

 


 



0 0
原创粉丝点击