1. 程式人生 > >OpenJ_Bailian - 2352 Stars(線段樹/樹狀陣列)

OpenJ_Bailian - 2352 Stars(線段樹/樹狀陣列)

題目連結

題意:統計幾級星的個數,對每個星星來說,有多少x,y都不超過他的星星,他就是幾級星(不包括自身);

題目給的星星是按y升序,y相等的時候x升序給出的,所以只需要知道每個星星前面有多少個x不超過他的就行;

很容易想到O(n2)的演算法,但時間複雜度太高;

這裡用線段樹或者樹狀陣列,每次輸入一次查詢一次x,在更新一次x;

用v表示結果,用t表示每個區間每個區間有多少個x的座標;

線段樹:

#include<cstdio>
#include<iostream>
using namespace std;

const int maxn=32000+10;//x,y的最大值
int t[maxn<<2],v[maxn];
int ans,n,x,y;

void query(int l,int r,int rt){//查詢x前面有多少個星星
    if(x>=r) ans += t[rt];
    else if(x<l) return;
    else{
        int mid = (l+r)>>1;
        query(l,mid,rt<<1);
        query(mid+1,r,rt<<1|1);
    }
}

void update(int l,int r,int rt){//更新x所在的所有區間,l=r的時候是找到了子節點
    if(l==r){
        t[rt]++;
        return;
    }
    int mid = (l+r)>>1;
    if(x<=mid) update(l,mid,rt<<1);
    else update(mid+1,r,rt<<1|1);
    t[rt]++;
}

int main()
{
    cin>>n;
    for(int i = 0;i < n;i++){
        cin>>x>>y;//輸入一個操作一次
        ans = 0;//ans是記錄前面有多少星
        query(0,maxn,1);
        v[ans]++;
        update(0,maxn,1);
    }
    for(int i = 0;i < n;i++)
        cout<<v[i]<<endl;
    return 0;
}

 

 

樹狀陣列:

#include<cstdio>
#include<iostream>
using namespace std;

const int maxn=32000+10;
int t[maxn],v[maxn];
int ans,n,x,y;

int lowbit(int x){//查詢最低位的1
    return x&(-x);
}

int query(int x){//查詢前x的和
    int ans = 0;//ans是結果
    while(x>0){//直到x減到0為止
        ans += t[x];//ans每次加上當前的值
        x -= lowbit(x);//x減去當前最低位的1
    }
    return ans;
}

void update(int x){//更新x的值
    while(x<=maxn){直到x增加到最大值
        t[x]++;//當前區間加一
        x += lowbit(x);//加上最低位的1
    }
    return;
}

int main()
{
    cin>>n;
    for(int i = 0;i < n;i++){
        cin>>x>>y;
        x++;//防止x是0時的陷阱,最後統計每個級別的星的數量,不會影響那個結果
        v[query(x)]++;
        update(x);
    }
    for(int i = 0;i < n;i++)
        cout<<v[i]<<endl;
    return 0;
}