hdu 3874 Necklace 线段树单点更新区间求和
http://acm.hdu.edu.cn/showproblem.php?pid=3874
题意:
给你n个数,然后给出m个的询问[l,r]问[l,r]中不同的数的和为多少?
思路:
单纯只考虑不同数的和的话,可能该数在之前出现过,后边又出现了,但是所求的区间不包括前边那个数,那么这个数就要被加进来。关键是如何维护该区间不包含重复计算同一个数。
首先我们离线处理所有询问,然后按r排序,然后遍历一边处理那些还没被加进线段树的数,如果他之前出现过了,那么就将之前的删除,然后再吧后边的加进来,这样既能保证同一个数只被计算的一次了,而且不影响后边的询问。
这里关键是按r排序之后的处理:
#include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define lc l,m,rt<<1 #define rc m + 1,r,rt<<1|1 #define pi acos(-1.0) #define L(x) (x) << 1 #define R(x) (x) << 1 | 1 #define MID(l, r) (l + r) >> 1 #define Min(x, y) (x) < (y) ? (x) : (y) #define Max(x, y) (x) < (y) ? (y) : (x) #define E(x) (1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x) printf("%I64d\n", x) #define lowbit(x) (x)&(-x) #define Read() freopen("din.txt", "r", stdin) #define Write() freopen("dout.txt", "w", stdout) #define M 200007 #define N 50007 #define ll __int64 using namespace std; const double eps = 1e-10; struct node { int l,r; int id; }nd[M]; ll val[4*N]; ll ans[M]; int a[N]; int off[1000007]; int n; void pushup(int rt) { val[rt] = val[rt<<1] + val[rt<<1|1]; } void build(int l,int r,int rt) { val[rt] = 0; if (l == r) return ; int m = (l + r)>>1; build(lc); build(rc); } void update(int pos,ll sc,int l,int r,int rt) { if (l == r) { val[rt] += sc; return ; } int m = (l + r)>>1; if (pos <= m) update(pos,sc,lc); else update(pos,sc,rc); pushup(rt); } ll query(int L,int R,int l,int r,int rt) { if (l >= L && r <= R) return val[rt]; ll res = 0; int m = (l + r)>>1; if (L <= m) res += query(L,R,lc); if (R > m) res += query(L,R,rc); return res; } int cmp(node a,node b) { return a.r < b.r; } int cmp2(node a,node b) { return a.id < b.id; } int main() { // Read(); int i; int T,n,m; scanf("%d",&T); while (T--) { scanf("%d",&n); for (i = 1; i <= n; ++i) scanf("%d",&a[i]); scanf("%d",&m); for (i = 0; i < m; ++i) { scanf("%d%d",&nd[i].l,&nd[i].r); nd[i].id = i; } sort(nd,nd + m,cmp); build(1,n,1); CL(off,0); int s = 1; for (i = 0; i < m; ++i) { while (s <= nd[i].r) { if (off[a[s]]) update(off[a[s]],-a[s],1,n,1); update(s,a[s],1,n,1); off[a[s]] = s; s++; } ans[nd[i].id] = query(nd[i].l,nd[i].r,1,n,1); } for (i = 0; i < m; ++i) { printf("%I64d\n",ans[i]); } } return 0; }