一维数组数组形式
int c[N], maxn; inline int Lowbit(int x){return x&(-x);} void change(int i, int x)//i点增量为x { while(i <= maxn) { c[i] += x; i += Lowbit(i); } } int sum(int x){//区间求和 [1,x] int ans = 0; for(int i = x; i >= 1; i -= Lowbit(i)) ans += c[i]; return ans; }
求区间最值:
struct Tree{ //手动初始化num数组 int lowbit(int x){ return x&(-x); } int a[100005], num[100005], maxn; void init(int len){ maxn = len; for (int i = 1; i <= maxn; i++){ a[i] = num[i]; for (int j = 1; j < lowbit(i); j <<= 1) a[i] = min(a[i], a[i - j]); } } void updata(int pos, int val){ num[pos] = val; for (int i = pos; i <= maxn; i += lowbit(i)){ a[i] = val; for (int j = 1; j < lowbit(i); j <<= 1) a[i] = min(a[i], a[i - j]); } return; } int query(int l, int r){ int ans = num[r]; while (true){ ans = min(ans, num[r]); if (r == l) break; for (r -= 1; r - l >= lowbit(r); r -= lowbit(r)) ans = min(ans, a[r]); } return ans; } }tree;
改段求段模版:
const int N = 4e5 + 100; template<class T> struct Tree{ T c[2][N]; int maxn; void init(int x){ maxn = x+10; memset(c, 0, sizeof c); } inline int lowbit(int x){ return x&-x; } T sum(T *b, int x){ T ans = 0; if (x == 0)ans = b[0]; while (x)ans += b[x], x -= lowbit(x); return ans; } void change(T *b, int x, T value){ if (x == 0)b[x] += value, x++; while (x <= maxn)b[x] += value, x += lowbit(x); } T get_pre(int r){ return sum(c[0], r) * r + sum(c[1], r); } void add(int l, int r, T value){//区间加权 change(c[0], l, value); change(c[0], r + 1, -value); change(c[1], l, value * (-l + 1)); change(c[1], r + 1, value * r); } T get(int l, int r){//区间求和 return get_pre(r) - get_pre(l - 1); } }; Tree<ll> x, y;
逆向使用时:
int c[N], maxn; inline int Lowbit(int x){return x&(-x);} int sum(int i)//单点更新i点改为x { int ans = 0; while(i <= maxn) { ans += c[i]; i += Lowbit(i); } return ans; } void change(int x, int value){//[1,x]增量为value for(int i = x; i >= 1; i -= Lowbit(i)) c[i] += value; }
树状数组求逆序数:
4 3 1 2
i = 1 : 插入4 : update(4,1),sum(4)返回1,那么当前比4大的为i - 1 = 0;
i = 2 : 插入3 : update(3,1),sum(3)返回1,那么当前比3大的为i - 1 = 1;
i = 3 : 插入1 : update(1,1),sum(1)返回1,那么当前比1大的为i - 1 = 2;
i = 4 : 插入2 : update(2,1),sum(2)返回2,那么当前比2大的为i - 2 = 2;
//逆序数 #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> using namespace std; const int N=1000005; #define LL __int64 LL cal[N],res[N],ans,ros[N]; LL n,maxn,minm; int lowbit(int x) {return x&-x;} LL getsum(int x) { LL s=0; for(;x>0;s+=cal[x],x-=lowbit(x)); return s; } void update(int x,int value) { for(;x<=maxn;cal[x]+=value,x+=lowbit(x)); } int find(int value) { int l=1,r=maxn,mid; while(l<=r) { mid=(l+r)>>1; if(ros[mid]==value) return mid; else if(ros[mid]>value) r=mid-1; else l=mid+1; } return -1; } int main() { int i,j,k; LL total; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) { scanf("%I64d",&res[i]); ros[i]=res[i]; } memset(cal,0,sizeof(cal)); sort(ros+1,ros+n+1); for(j=1,i=2;i<=n;i++) { if(ros[i]!=ros[j]) ros[++j]=ros[i]; } maxn=j; for(i=1,total=0;i<=n;i++) { k=find(res[i]); update(k,1); total+=i-getsum(k); } printf("%I64d\n",total); } return 0; } /* 3 3 1 2 ans=2 */
二维树状数组支持对矩阵的子块操作,单点操作,子块求和
const int MAX=1200; int c[MAX][MAX]; int n; int LowBit(int t){ return t&(-t);} int Sum(int endx,int endy)//求和 求矩阵[1,1]-[endx,endy]的和 { int sum=0; int temp=endy; while(endx>0) { endy=temp;// while (endy>0) { sum+=c[endx][endy]; endy-=LowBit(endy); } endx-=LowBit(endx); } return sum; } void add(int addx,int addy,int num)//在[x,y]位置上加上 num { int temp=addy; while (addx <=n) { addy=temp; while(addy<=n) { c[addx][addy]+=num; addy+=LowBit(addy); } addx+=LowBit(addx); } } int GetSum(int l,int b,int r,int t)//求[l,b]-[r,t]的和 若是点 则是GetSum(x,y,x,y) { return Sum(r,t)-Sum(r,b-1)-Sum(l-1,t)+Sum(l-1,b-1); } void updat(int x,int y,int val){ //更新[1,1]-[x,y]区间的点 都+val for (;x<=n;x+=LowBit(x)) for (int i=y;i<=n;i+=LowBit(i)) c[x][i]+=val; } scanf("%d%d%d%d",&x1,&y1,&x2,&y2); updat(x1, y1, 1); updat(x2 + 1, y2 + 1, -1); updat(x1, y2 + 1, -1); updat(x2 + 1, y1, -1);