【树状数组+离线查询】HDU 3333 Turing Tree
https://www.bnuoj.com/v3/contest_show.php?cid=9149#problem/H
【题意】
给定一个数组,查询任意区间内不同数字之和。
(n<=30000,Q<=100000,每个数字<=1 000 000 000)
【思路】
要算任意区间内不同数字之和,如果我们从左到右依次处理,每次只保留最右边出现的数字,处理以当前数字为右端点的查询,就能做到“不同数字之和”,即不重不漏。因此我们要离线处理查询,按记录每个数作为右端点的所有查询区间。这里要用到vector记录固定右端点后每个所有查询区间的左端点和查询ID,要用map或unorderd_map记录每个数之前出现的位置(要把那个位置的删掉)
【Accepted】
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 #include<vector> 8 #include<map> 9 #include<unordered_map> 10 using namespace std; 11 const int maxn=1e5+3; 12 typedef long long ll; 13 int n,m; 14 vector<pair<int,int> > p[maxn]; 15 map<ll,int> pre; 16 17 ll tree[maxn]; 18 ll a[maxn]; 19 ll ans[maxn]; 20 void init() 21 { 22 memset(ans,0,sizeof(ans)); 23 for(int i=1;i<=n;i++) 24 { 25 tree[i]=0LL; 26 } 27 pre.clear(); 28 } 29 int lowbit(int x) 30 { 31 return x&(-x); 32 } 33 void add(int k,ll x) 34 { 35 while(k<=n) 36 { 37 tree[k]+=x; 38 k+=lowbit(k); 39 } 40 } 41 42 ll query(int k) 43 { 44 ll res=0LL; 45 while(k) 46 { 47 res+=tree[k]; 48 k-=lowbit(k); 49 } 50 return res; 51 } 52 ll query(int l,int r) 53 { 54 return query(r)-query(l-1); 55 } 56 int main() 57 { 58 int T; 59 scanf("%d",&T); 60 while(T--) 61 { 62 scanf("%d",&n); 63 init(); 64 for(int i=1;i<=n;i++) 65 { 66 cin>>a[i]; 67 p[i].clear(); 68 } 69 scanf("%d",&m); 70 int u,v; 71 for(int i=1;i<=m;i++) 72 { 73 scanf("%d%d",&u,&v); 74 p[v].push_back(make_pair(u,i)); 75 } 76 for(int i=1;i<=n;i++) 77 { 78 if(pre.count(a[i])) 79 { 80 add(pre[a[i]],-a[i]); 81 } 82 pre[a[i]]=i; 83 add(i,a[i]); 84 int sz=p[i].size(); 85 for(int k=0;k<sz;k++) 86 { 87 ans[p[i][k].second]=query(p[i][k].first,i); 88 } 89 } 90 for(int i=1;i<=m;i++) 91 { 92 cout<<ans[i]<<endl; 93 } 94 } 95 return 0; 96 }