树状数组是普通数组的升级版本,举个例子在求和时候复杂度为log(n)但是普通的是n(不知道是不是复杂度还不怎么会),可以减少花费的时间,有时候也可以用来求逆序数(归并也可以 但是还没看过)。
树状数组最经典的图是这样的:
图中可以看出C数组就是树状数组,可以看出其中的规律,定义一个i,如果i是奇数那么树状数组就是本身,如果i是偶数那么就要看i%2了,如果为0的话那么就是1~i,否则就是
i和i-1。
int getbit(int i)
{
return i&(-i);
}
这个函数可以很好的实现这个功能,如果不懂什么意思给个链接看看就好 http://zhidao.baidu.com/link?url=_LZztMQn74VM8tWCGQj4jTSQRTJfcIXmBw9APRC1OHhVJGqLIALOC1cndAiCUxH4zkBpI4dUCz_IhGauxxYa1_
这个只是第一步然后可以实现很多功能下面就举两个例子:
求和
int getsum(int i)
{
int ans=0;
while(i>0)
{
ans+=c[i];
i-=getbit(i);
}
return ans;
}
区间修改 让a[2]-1:
void update(int p,int i)//p输入2
{
while(i<=n)
{
c[i]+=p;
i+=getbit(i);
}
}
POJ3067就是可以用树状数组求逆序数来做
Description
Input
Output
Test case (case number): (number of crossings)
Sample Input
1 3 4 4 1 4 2 3 3 2 3 1
Sample Output
Test case 1: 5
很明显了 就是让你求逆序数,但是这道题目的数据很大需要64位来定义SUM,
AC代码
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct q
{
int l,r;
}c[1001*1001];
int n,m,k;
long long w[1001];
int lowbit(int a)
{
return a&(-a);
}
int cmp(struct q a,struct q b)
{
if(a.l!=b.l)return a.l<b.l;
else return a.r<b.r;
}
void update(int p,int c)
{
while(p<=m)
{
w[p]+=c;
p+=lowbit(p);
}
}
long long getsum(int c)
{
long long sum=0;
while(c>0)
{
sum+=w[c];
c-=lowbit(c);
}
return sum;
}
int main()
{
int t,n,i,j=0;
while(~scanf("%d",&t))
{
while(t--)
{
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=k;i++)
scanf("%d%d",&c[i].l,&c[i].r);
memset(w,0,sizeof(w));
sort(c+1,c+1+k,cmp);
long long ans=0;
for(i=1;i<=k;i++)
{
update(c[i].r,1);
ans+=i-getsum(c[i].r);//减掉当前W数组的值就是比它大的数目
}
printf("Test case %d: %I64d\n",++j,ans);
}
}
return 0;
}