HDU:3333 Turing Tree (樹狀陣列+離線處理+雜湊+貪心)
阿新 • • 發佈:2019-02-16
題意:給一個數組,每次查詢輸出區間內不重複數字的和。
思路:
用字首和的思想可以輕易求得區間的和,但是對於重複數字這點很難處理。線上很難下手,考慮離線處理。
將所有查詢區間從右端點由小到大排序,遍歷陣列中的每個數字,每次將該數字上次出現位置的值在樹狀陣列中改為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; }