题意:
查询区间和,重复的数字只计算一遍
思路:
先离线读入所有区间,然后按照区间右端点从小到大排序。
从数组的第一个数开始,依次修改bit直到每个区间的右端点,然后bit求区间和。
修改方式:用一个map记录当前数字是否已经出现过以及出现过的上一个位置,然后将该位置改为0,并更新一下map即可。
(因为一旦出现重复数字,其实只有该区间中的最后一个数字是起作用的,在他之前的都应该忽略,设为0)
code:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #include<vector> #include<string> #include<queue> #include<map> #include<set> #include<cmath> #include<cstdlib> using namespace std; #define INF 0x3f3f3f3f #define PI acos(-1.0) #define mem(a, b) memset(a, b, sizeof(a)) #define mod 1000000007 typedef pair<int,int> pii; typedef long long LL; //------------------------------ const int maxn = 30005; const int maxq = 100005; struct node{ int s, e, id; bool operator < (const node nt) const{ if(e != nt.e) return e < nt.e; else return s < nt.s; } }qujian[maxq]; int n,q; LL a[maxn]; LL ans[maxq]; struct BIT { long long C[maxn]; void init() { memset(C, 0, sizeof(C)); } int lowbit(int x) { return -x&x; } long long get_Sum(int x) { long long ret = 0; while(x > 0) { ret += C[x]; x -= lowbit(x); } return ret; } void add(int x,long long v) { while(x <= n) { C[x] += v; x += lowbit(x); } } }bit; void init(){ scanf("%d",&n); for(int i = 1; i <= n; i++){ cin >> a[i]; } scanf("%d",&q); int st, ed; for(int i = 0; i < q; i++){ scanf("%d%d",&st, &ed); qujian[i].s = st; qujian[i].e = ed; qujian[i].id = i; } } map<long long, int> ma; void solve(){ sort(qujian, qujian+q); ma.clear(); bit.init(); int start_ = 1; for(int i = 0; i < q; i++){ for(int j = start_; j <= qujian[i].e; j++){ if(ma.count(a[j])){ bit.add(ma[a[j]],-a[j]); } bit.add(j,a[j]); ma[a[j]] = j; } ans[qujian[i].id] = bit.get_Sum(qujian[i].e) - bit.get_Sum(qujian[i].s-1); start_ = qujian[i].e + 1; } for(int i = 0; i < q; i++){ cout << ans[i] << endl; } } int main(){ int t; scanf("%d",&t); while(t--){ init(); solve(); } return 0; }
一是用long long
而是要从第一个数开始修改,这个地方我刚开始从第一个区间的左端点开始更新,这样显然是不对的。