題目-樓蘭圖騰-樹狀數組

在完成了分配任務之後,西部314來到了樓蘭古城的西部。相傳很久以前這片土地上(比樓蘭古城還早)生活着兩個部落,一個部落崇拜尖刀(‘V’),一個部落崇拜鐵鍬(‘∧’),他們分別用V和∧的形狀來代表各自部落的圖騰。西部314在樓蘭古城的下面發現了一幅巨大的壁畫,壁畫上被標記出了N個點,經測量發現這N個點的水平位置和豎直位置是兩兩不同的。西部314認爲這幅壁畫所包含的信息與這N個點的相對位置有關,因此不妨設座標分別爲(1,y1),(2,y2),…,(n,yn)(1,y1),(2,y2),…,(n,yn)

,其中y1y1

~ynyn

是1到n的一個排列。西部314打算研究這幅壁畫中包含着多少個圖騰。如果三個點(i,yi),(j,yj),(k,yk)(i,yi),(j,yj),(k,yk)

滿足1≤i<j<k≤n且yi>yj,yj<yk1≤i<j<k≤n且yi>yj,yj<yk

,則稱這三個點構成V圖騰;如果三個點(i,yi),(j,yj),(k,yk)(i,yi),(j,yj),(k,yk)

滿足1≤i<j<k≤n且yi<yj,yj>yk1≤i<j<k≤n且yi<yj,yj>yk

,則稱這三個點構成∧圖騰;西部314想知道,這n個點中兩個部落圖騰的數目。因此,你需要編寫一個程序來求出V的個數和∧的個數。輸入格式第一行一個數n。第二行是n個數,分別代表y1,y2,…,yny1,y2,…,yn

。輸出格式兩個數,中間用空格隔開,依次爲V的個數和∧的個數。數據範圍對於所有數據,n≤200000n≤200000

,且輸出答案不會超過int64。輸入樣例:5
1 5 3 2 4
輸出樣例:3 4

樹狀數組的分析:樹狀數組的用法很簡單,但是想要理解卻不太容易,我這裏簡單講一下樹狀數組:他的關鍵還是二進制數,把一個區間的和分爲很多個區間的和,它主要執行倆個功能,第一個功能是在x處插入c代碼如下:

void add(int x,int c){
 for(int i=x;i<=n;i+=lowbit(i))    tr[i]+=c;
}

如何理解這個函數:tr[I]數組表示的是以i結尾長度爲lowbit(i)的一個區間內所有數的和,當在I處插入一個數的·時候,把一個很大的區間分成幾個小區間每一個區間的長度都是當前的lowbit(i),當在I處插入c,它上面的tr數組也要增加c,而當這個數的最後一個1加1的話,他就會向上進一位數,所以這樣就能增加一個數。
第二個函數是求前x個數的和,代碼如下

int sum(int x){
 int res=0;
 for(int i=x;i;i-=lowbit(x))       res+=tr[i];
 return res;
}

這個代碼相較於上個代碼就很好理解了,就是把x分成的每個tr區間的和加起來就可以了。
接下來就是這道題的思路:以V圖騰爲例,分爲任何一個點爲v的底下的那個點,他左面的比他大的點的數量乘上右面的比它大的點的數量就可以了,而求他左面的比他大的點,就從左向右枚舉,把他左面的點都加進樹狀數組裏面,然後求出差即可,同理,右面的點也是。
ac的代碼如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
typedef long long LL;
int n;
const int N=200010;
int a[N];
int tr[N];
int gao[N],di[N];
using namespace std;
int lowbit(int x){
 return x&-x;
}
void add(int x,int c){
 for(int i=x;i<=n;i+=lowbit(i))    tr[i]+=c;
}
int sum(int x){
 int res=0;
 for(int i=x;i;i-=lowbit(x))       res+=tr[i];
 return res;
}
int main(){
 scanf("%d",&n);
    for(int i=1;i<=n;i++)    scanf("%d",&a[i]);
    for(int i=1;i<=n;i++){
     int y=a[i];
     gao[i]=sum(n)-sum(y);
     di[i]=sum(y-1);
     add(y,1);
 }
 memset(tr,0,sizeof tr);
 LL res1=0,res2=0;
 for(int i=n;i;i--){
  int y=a[i];
     res1+=gao[i]*(LL)sum(n)-sum(y);
     res2+=di[i]*(LL)sum(y-1);
     add(y,1);
 }
 cout<<res1<<" "<<res2<<endl;
 return 0;
}
發佈了42 篇原創文章 · 獲贊 33 · 訪問量 3956
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章