1. 程式人生 > >HDU 4325 離散化+樹狀數組 或者 不使用樹狀數組

HDU 4325 離散化+樹狀數組 或者 不使用樹狀數組

eof its ret bit 。。 通過 一個 ase 樹狀

題意:給出一些花的開放時間段,然後詢問某個時間點有幾朵花正在開放。

由於ti<1e9,我們需要先將時間離散化,然後將時間點抽象為一個數組中的點,顯然,我們需要進行區間更新和單點查詢,可以考慮線段樹與樹狀數組兩種做法,一般的,樹狀數組是用來維護區間和與單點修改的,那麽,如何通過樹狀數組進行區間更新和單點查詢呢,聯想到差分數組,差分數組可以在o(1)的時間內進行區間的更新,但是單點查詢的效率為o(n),顯然不能用於處理此題,這時,考慮樹狀數組維護差分數組,就可以o(logn)地進行區間更新(更新差分數組的 l, r+1即可,使sub[l]++,sub[r+1]--),o(logn)地查詢單點值(求差分數組前綴和)//樹狀數組維護差分數

#include<bits/stdc++.h

#define N 100005

#define mod 998244353
using namespace std;
typedef long long ll;
int sub[N<<1],n,l[N],r[N],tim[N],nn;
int lowbit(int x){ return x&-x;};
int add(int x,int val)
{
    while(x<=nn)
    {
        sub[x]+=val;
        x+=lowbit(x);
    }
}
int query(int
x) { int ans=0; while (x>0) { ans+=sub[x]; x-=lowbit(x); } return ans; } int main() { int t; cin>>t; for(int ca=1;ca<=t;ca++) { memset(sub,0, sizeof(sub)); vector<int>mp; int q,L,R; cin>>n>>q;
for(int i=1;i<=n;i++) { scanf("%d%d",l+i,r+i); mp.push_back(l[i]); mp.push_back(r[i]); } for(int i=1;i<=q;i++) { scanf("%d",tim+i); mp.push_back(tim[i]); } nn=mp.size(); sort(mp.begin(),mp.end()); unique(mp.begin(),mp.end()); for(int i=1;i<=n;i++) { L=lower_bound(mp.begin(),mp.end(),l[i])-mp.begin()+1; R=lower_bound(mp.begin(),mp.end(),r[i])-mp.begin()+1; add(L,1); add(R+1,-1); } //for(int i=1;i<=mp.size();i++)cerr<<query(i)<<endl; printf("Case #%d:\n",ca); for(int i=1;i<=q;i++) { int pos=lower_bound(mp.begin(),mp.end(),tim[i])-mp.begin()+1; printf("%d\n",query(pos)); } } return 0; }

嚶嚶嚶~~博客寫完,我就後悔了,本題的區間更新和單點查詢操作是分開的,那麽我為什麽搞這麽麻煩還用樹狀數組,直接差分數組求和後不就能o(1)單點查詢了嗎。。但是總體復雜度不變,仍為o(nlogn)
(n為離散化後,映射中點的個數,),常數降低了很多,,雖然運行時間只是由312ms到296ms,但是寫起來簡單了許多,以下是沒有使用樹狀數組的ac代碼

//樹狀數組維護差分數組
#include<bits/stdc++.h>
#define N 100005
#define mod 998244353
using namespace std;
typedef long long ll;
int sub[N<<1],n,l[N],r[N],tim[N],nn;
int main()
{
    int t;
    cin>>t;
    for(int ca=1;ca<=t;ca++)
    {
        memset(sub,0, sizeof(sub));
        vector<int>mp;
        int q,L,R;
        cin>>n>>q;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",l+i,r+i);
            mp.push_back(l[i]);
            mp.push_back(r[i]);
        }
        for(int i=1;i<=q;i++)
        {
            scanf("%d",tim+i);
            mp.push_back(tim[i]);
        }
        nn=mp.size();
        sort(mp.begin(),mp.end());
        unique(mp.begin(),mp.end());
        for(int i=1;i<=n;i++)
        {
            L=lower_bound(mp.begin(),mp.end(),l[i])-mp.begin()+1;
            R=lower_bound(mp.begin(),mp.end(),r[i])-mp.begin()+1;
            sub[L]++;
            sub[R+1]--;
        }
        for(int i=1;i<=nn;i++)sub[i]+=sub[i-1];
        printf("Case #%d:\n",ca);
        for(int i=1;i<=q;i++)
        {
            int pos=lower_bound(mp.begin(),mp.end(),tim[i])-mp.begin()+1;
            printf("%d\n",sub[pos]);
        }
    }
    return 0;
}

事實證明,只要多思考,問題就會更簡單。算是一點小小的啟發吧



HDU 4325 離散化+樹狀數組 或者 不使用樹狀數組