菜鸡冒泡~~ 有锅请各位dalao指出
~~ first of all
先交代故事发生的背景.........
关于lowbit的函数介绍(so easy) lowbit是找最后一位是一的位数 ●在计算机中,负数的存储为(以八进制为例,-10 就是10001010※第一位是符号位 对于正数来说,原码,反码,补码都是同一个,对于负数来说,反码就是除去符号位以外,其余的取反 补码是反码最后加一,(加爆了也不用管,加就是了)) ●按位& 例如1&1=1,是两边同时满足才可以 ●一个数和他的相反数用&,则可以求出最后一位是1的位置(就是lowbit的代码实现)(※但要注意的是如果一个数是2的k次方,那么这个数的lowbit还是这个数,手动实现验证) ★关于树状数组,一般是给某一个数加上一个值,还有就是询问某个区间的和, 给某一个数加上一个值,要求更新和这个数有关的所有数,用树状数组可以节省时间大约是O(nlogn) 每次都要update,用c数组去存a数组的值,类似于一个树开始的时候直接加一个值就可以,之后的每次增加某一个数的值要求是每次都要update 而从一个点找到下一个应该被更新的点用的就是lowbit(x)+x; 树状数组中c数组的所代表的数字取决于lowbit的值 例如说lowbit 1=1那么c1就是一个数的和 lowbit 2=2那么c2就是两个数的和,lowbit3=1那么c1就是一个数的和。。。。。。
/*
关于lowbit的函数介绍(so easy)
lowbit是找最后一位是一的位数
●在计算机中,负数的存储为(以八进制为例,-10 就是10001010※第一位是符号位
对于正数来说,原码,反码,补码都是同一个,对于负数来说,反码就是除去符号位以外,其余的取反
补码是反码最后加一,(加爆了也不用管,加就是了))
●按位& 例如1&1=1,是两边同时满足才可以
●一个数和他的相反数用&,则可以求出最后一位是1的位置(就是lowbit的代码实现)(※但要注意的是如果一个数是2的k次方,那么这个数的lowbit还是这个数,手动实现验证)
★关于树状数组,一般是给某一个数加上一个值,还有就是询问某个区间的和,
给某一个数加上一个值,要求更新和这个数有关的所有数,用树状数组可以节省时间大约是O(nlogn)
每次都要update,用c数组去存a数组的值,类似于一个树开始的时候直接加一个值就可以,之后的每次增加某一个数的值要求是每次都要update
而从一个点找到下一个应该被更新的点用的就是lowbit(x)+x;
树状数组中c数组的所代表的数字取决于lowbit的值
例如说lowbit 1=1那么c1就是一个数的和 lowbit 2=2那么c2就是两个数的和,lowbit3=1那么c1就是一个数的和。。。。。。
*/
#include<iostream>
#include<cstdio>
#include<stdio.h>
using namespace std;
int n,m;int c[5000005];
int lowbit(int ii)
{
return ii&(-ii);
}
void update(int x,int k)
{
while(x<=n)
{
c[x]+=k;
x=x+lowbit(x);
}
}
int getsum(int x)
{
int sum=0;
while(x!=0)
{
sum+=c[x];
x=x-lowbit(x);
}
return sum;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int a;
cin>>a;
update(i,a);
}
for(int i=1;i<=m;i++)
{
int p,x,y;
cin>>p>>x>>y;
if(p==1)
{
update(x,y);
}
if(p==2)
{
int ckwnb=getsum(y)-getsum(x-1);
cout<<ckwnb<<endl;
}
}
}
应用如下
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdio>
#include<stdio.h>
using namespace std;
long long int n;long long int c[500015]={0};
struct strr{
long long int id,wei;
}map[500005];
long long int com(strr x,strr y)
{
if(x.wei!=y.wei)
return x.wei>y.wei;
if(x.wei==y.wei)
return x.id>y.id;
}
long long int lowbit(int l)
{
return l&(-l);
}
void update(int x)
{
while(x<=n)
{
c[x]++;
x=x+lowbit(x);
}
}
long long int getsum(int x)
{
long long int sum=0;
while(x>0)
{
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
int main()
{
long long int ans=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
cin>>map[i].wei;
map[i].id=i;
}
sort(map+1,map+n+1,com);
for(int i=1;i<=n;i++)
{
update(map[i].id);
ans+=getsum(map[i].id-1);
}
cout<<ans;
return 0;
}
/*make an summary
将一个数的id和这个数的值联系到一起,对值进行排序,但是 实际用到的还是这个数的地址
用树状数组对id排玩顺序以后的数组当做原来的c数组
这是要记得用一个ans变量来记录目前已经有多少是符合要求的了,不断的运用加法即可,
比如说一开始的原数组为5 4 2 6 3 1,按着从大到小拍完顺序以后,可以得到以下的id顺序为4 1 2 5 3 6
此时,把新得到的id作为c数组,不断的加(◆原理和简单)
{
¤第一个数为4
先放进去4 ,这是4是最大的,(要知道,现在加进去的数的id如果很大,(比已经加进去的还要打,就说明这的数的id大但是数目小,这时候看看传输组中
已经加进去的,如果id比这个小但是已经放进去了,就只能说明已经放进去的数比这个id大的数数值大,就符合逆序对的要求,这样就比较明显了
只要在每放一个数的时候,找出id比当前值小的就ok了),于是有了以上代码,◎◎◎◎◎◎◎◎)
last but not least
求逆序对数目的时候要用到树状数组(这些都是小事,but 还挺好用的)
} */