1. 程式人生 > >HDU:3333 Turing Tree (樹狀陣列+離線處理+雜湊+貪心)

HDU:3333 Turing Tree (樹狀陣列+離線處理+雜湊+貪心)

題意:給一個數組,每次查詢輸出區間內不重複數字的和。

思路:

用字首和的思想可以輕易求得區間的和,但是對於重複數字這點很難處理。線上很難下手,考慮離線處理。

將所有查詢區間從右端點由小到大排序,遍歷陣列中的每個數字,每次將該數字上次出現位置的值在樹狀陣列中改為0,再記錄當前位置,在樹狀陣列中修改為當前的數值。這樣可以保證在接下來的查詢中該數字只出現了一次。這是貪心的思想,只保留最可能被以後區間查詢的位置。如果當前位置是某個查詢區間的右端點,這時候就可以查詢了。最後再根據查詢區間的編號排序輸出即可了。

注意樹狀陣列查詢0位置會出現死迴圈。

HDU上long long 需要使用I64d。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
#define ll long long
#define MAXN 100005
using namespace std;
int n;
map<int,int> pos;
struct Segment
{
    int num,left,right;
    ll ans;
    Segment(int a=0,int b=0,int c=0):num(a),left(b),right(c)
    {
        ans=0;
    }
    bool operator <(const Segment &p) const
    {
        return right<p.right;
    }
};
bool cmp(Segment a,Segment b)
{
    return a.num<b.num;
}
struct BIT
{
    ll dat[MAXN];
    int lowbit(int x)
    {
        return -x&x;
    }
    void clear()
    {
        memset(dat,0,sizeof(dat));
    }
    void add(int x,ll val)
    {
        while(x<=n)
        {
            dat[x]+=val;
            x+=lowbit(x);
        }
    }
    ll sum(int x)
    {
        ll s=0;
        while(x>0)
        {
            s+=dat[x];
            x-=lowbit(x);
        }
        return s;
    }
    void modify(int x,ll val)
    {
        if(x==0) return ;
        ll t=sum(x)-sum(x-1);
        add(x,-t+val);
    }
};
int arr[MAXN];
vector<Segment> vec;
BIT tree;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        pos.clear();
        for(int i=1; i<=n; ++i)
            scanf("%d",&arr[i]);
        int q;
        scanf("%d",&q);
        vec.clear();
        for(int i=1; i<=q; ++i)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            vec.push_back(Segment (i,x,y));
        }
        sort(vec.begin(),vec.end());
        tree.clear();
        for(int i=1,j=0; i<=n&&j<vec.size(); ++i)
        {
            tree.modify(pos[arr[i]],0);
            tree.modify(i,arr[i]);
            pos[arr[i]]=i;
            while(j<vec.size()&&i==vec[j].right)
            {
                vec[j].ans=tree.sum(vec[j].right)-tree.sum(vec[j].left-1);
                j++;

            }
        }
        sort(vec.begin(),vec.end(),cmp);
        for(int i=0; i<vec.size(); ++i)
            printf("%I64d\n",vec[i].ans);
    }
    return 0;
}