1. 程式人生 > 實用技巧 >樹狀陣列模板

樹狀陣列模板

主要講一下狀陣列的建立和逆序對的求解方法

樹狀陣列:

  • 修改和查詢的複雜度均為\(O(\log n)\)相比線段樹的係數要少很多。

採用了二進位制的方法建樹,僅有左兒子而無右兒子.

建樹過程:

void update(int x,int y){//給x位置加上y
    while(x<=n){
        d[x]+=y;x+=lowbit(x);
    }
}

建樹時要一個一個更新建樹,比如說我給\(a[2]\)+1,那麼本來的\(a[4],a[8]\)都要加上1,具體的新增過程可以看建樹的程式碼

求和過程:

int get_sum(int x){
    int ans=0;
    while(x){
        ans+=d[x];x-=lowbit(x);
    }
    return ans;
}

在求和時是一層一層去求解的,比如說我求\(sum[7]\),我需要遍歷所有的\(lowbit\),也即sum[7]=a[7]+a[6]+a[4]

​ 具體過程:

​ 7=\(111\)那麼我們遍歷二進位制時候先加上\(111=7\)位置數,然後繼續遍歷下一個子節點\(110=6\),然後繼續下一個子節點\(100\)這個過程是和\(lowbit\)有關的。

普通逆序對

​ 在插入前先掃一遍,之前插入的數中比他大的數的個數之和也就是\(et_sum(n)-get_sum(x)\),然後每次對每個數更新都是\(update(x,1)\),給\(x\)位置加上1,也就是這個位置的數的個數。

然後跑一邊:

for(int i=1;i<=n;++i){
    ans+=ask(sum)-ask(d[i]);
    update(d[i],1);
}
https://ac.nowcoder.com/acm/problem/15163

翻轉逆序對

每次翻轉:\(C_{n}^{2}-原來的逆序對個數\)就是現在的逆序對個數,然後根據奇偶性

假設逆序對的個數為\(ans\)則:反轉後

\(ans=ans-x+C_n^2-x\)顯然\(-2x\)為偶數,所以只需要判斷\(ans和C_n^2\)

\(C_n^2,ans\)都為奇數時,\(ans\)變為偶數,也就是翻轉後逆序對的個數為偶數個。

這個變化是可以看出只有當\(C_n^2\)

為奇數時才會變化\(ans\)的奇偶性

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define debug(case,x); cout<<case<<"  : "<<x<<endl;
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
using namespace std;
const int maxn = 5e5 + 10;
struct cmp {
    bool operator ()(const int& a, const int& b)const {
        return a > b;
    }
};
template<typename T>void read(T &res) {
	bool flag=false;
	char ch;
	while(!isdigit(ch=getchar()))
		(ch=='-')&&(flag=true);
	for(res=ch-48;isdigit(ch=getchar());
	res=(res<<1)+(res<<3)+ch - 48);
	flag&&(res=-res);
}
int d[maxn];int n;
inline int lowbit(int x){return -x&x;}

int get_sum(int x){
    int ans=0;
    while(x){
        ans+=d[x];x-=lowbit(x);
    }
    return ans;
}

void update(int x,int y){
    while(x<=n){
        d[x]+=y;x+=lowbit(x);
    }
}
int main()
{
    int tt,t;scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d",&tt);
        t+=get_sum(n)-get_sum(tt);
        update(tt,1);
    }
    t=t&1;
    int m;scanf("%d",&m);
    while(m--){
        int l,r;scanf("%d%d",&l,&r);
        int tmp=(r-l+1)*(r-l)>>1;
        if(tmp&1)t=1-t;
        if(t&1)printf("dislike\n");
        else printf("like\n");
    }

}
https://ac.nowcoder.com/acm/problem/20861