樹狀數組題目合集

單點更新 區間查詢php

敵兵佈陣 html

坑點:cin cout 一直超時  改爲 scanf 和printf  就過了算法

/*輸入
t樣例
N(N<=50000) 
第i個正整數ai表明第i個工兵營地裏開始時有ai我的(1<=ai<=50)。

接下來每行有一條命令,命令有4種形式:
(1) Add i j,i和j爲正整數,表示第i個營地增長j我的(j不超過30)
(2)Sub i j ,i和j爲正整數,表示第i個營地減小j我的(j不超過30);
(3)Query i j ,i和j爲正整數,i<=j,表示詢問第i到第j個營地的總人數;
(4)End 表示結束,這條命令在每組數據最後出現;

1
10
1 2 3 4 5 6 7 8 9 10
Query 1 3
Add 3 6
Query 2 7
Sub 10 2
Add 6 3
Query 3 10
End  


輸出
Case 1:
6
33
59
*/

#include <string.h>
#include <stdio.h>
using namespace std;
int n,t[50005];
int lowbit(int x)
{
     return x&(-x);
}

void update(int x,int val)//單點更新
{
    while(x<=n){
        
        t[x]+=val;
        x+=lowbit(x);//由葉子節點向上更新樹狀數組C,從左往右更新
    }
}

int ask(int x)//求區間[1,i]內全部元素的和 即求前綴和
{
    int ans=0;
    while(x>0){
        ans+=t[x];//從右往左累加求和
        x-=lowbit(x);
    }
    return ans;
}

int main()
{
    int tt,cnt=0,b,c,i,a;
    char s[10];
    scanf("%d",&tt);
    while(tt--)
    {
        scanf("%d",&n);
        memset(t,0,sizeof(t));
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a);
            update(i,a);
        }
         printf("Case %d:\n",++cnt);
        while(scanf("%s",s))
        {
             if(s[0]=='E') break;
             scanf("%d%d",&c,&b);
             if(s[0]=='S') update(c,-b);
            
            if(s[0]=='A') update(c,b);
            
            if(s[0]=='Q') 
            {
                printf("%d\n",ask(b)-ask(c-1)); 
            }               
        }
    }
    return 0;
} 
View Code

 Ultra-QuickSort數組

這個題把數據離散化了 ,利用樹狀數組求數據的逆序對 ,即超快排的交換次數。ide

/*
在此問題中,您必須分析特定的排序算法。該算法經過交換兩個相鄰的序列元素,
直到該序列以升序排序,來處理n個不一樣整數的序列。對於輸入序列 
9 1 0 5 4,

Ultra-QuickSort產生輸出 
0 1 4 5 9。
您的任務是肯定Ultra-QuickSort須要執行多少次交換操做才能對給定的輸入序列進行排序。

輸入項
輸入包含幾個測試用例。每一個測試用例均以包含單個整數n <500,000(輸入序列的長度)的一行開頭。
接下來的n行中的每行都包含一個整數,即0≤a [i]≤999,999,999,即第i個輸入序列元素。輸入由長度爲n = 0的序列終止。
不得處理此序列。

輸出量
對於每一個輸入序列,程序將打印一行包含整數op的單行,op是對給定輸入序列進行排序所需的最小交換操做數。

Input 
5
9
1
0
5
4
3
1
2
3
0

Output 
6
0

*/ 

#include <string.h>
#include <stdio.h>
#include <algorithm>
#define maxn 500010
using namespace std;
long long int  n, a[maxn], b[maxn],t[maxn];
int lowbit(int x)
{
     return x&(-x);
}

void update(int x,int val)//單點更新w
{
    while(x<=n){
        
        t[x]+=val;
        x+=lowbit(x);//由葉子節點向上更新樹狀數組C,從左往右更新
    }
}

long long int ask(int x)//求區間[1,i]內全部元素的和 即求前綴和
{
    long long int  ans=0;
    while(x>0){
        ans+=t[x];//從右往左累加求和
        x-=lowbit(x);
    }
    return ans;
}



int main()
{
    long long int ans=0;
    //這裏如下標1爲序列的起點,通常狀況下從0開始也能夠
    while(scanf("%lld",&n))
    {
        if(!n) break;
        for(int i = 1;i <= n;i++)
        {
            scanf("%lld", &a[i]);
            b[i] = a[i];//b是一個臨時數組,用來獲得離散化的映射關係
        }
        //下面使用了STL中的sort(排序),unique(去重),lower_bound(查找)函數
        sort(b + 1, b + n + 1);//排序
        int size = unique(b + 1, b + 1 + n) - b - 1;//去重,並得到去重後的長度size
        for(int i = 1;i <= n;i++)
        {
            a[i] = lower_bound(b + 1, b + 1 + size, a[i]) - b;//經過二分查找,快速地把元素和映射對應起來
            update(a[i],1);
            ans +=(i-ask(a[i])); 
            
        }
        printf("%lld\n",ans);
        ans=0;
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        memset(t,0,sizeof(t));
    }
    return 0;
} 
View Code
相關文章
相關標籤/搜索