hdu-3333 Turing Tree 离线区间+树状数组(区间不同数的和)

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=3333

题目大意:

给出一数组,以及m个查询区间,每次查询该区间不同数字的和。相同数字只加一次。

解题思路:

离线区间,按照区间右端点进行排序。

这样可以从左到右扫一遍,用尺取法一个一个将数字放入树状数组中。

如果这个数字已经在树状数组里面,记录之前的下标,再从树状数组中删去之前下标的这个数字,在当前下标添加该数字。这样可以保证每一步操作,都会使得树状数组中没有重复元素。这样可以直接用树状数组求不同数字的和。

求区间种类数也是这样做。

 1 #include<bits/stdc++.h>
 2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf
 3 #define Max(a, b) ((a) > (b) ? (a) : (b))
 4 #define Min(a, b) ((a) < (b) ? (a) : (b))
 5 #define Mem(a) memset(a, 0, sizeof(a))
 6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1))
 7 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂
 8 using namespace std;
 9 inline int read()
10 {
11     int x=0,f=1;char ch=getchar();
12     while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
13     while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 
17 typedef long long ll;
18 const int maxn = 100000 + 10;
19 const int MOD = 1000000007;//const引用更快,宏定义也更快
20 ll a[maxn];//树状数组
21 ll c[maxn];//原数组
22 map<ll, int>Last;//记录上一次出现该值的下标
23 int n;
24 int lowbit(int x)
25 {
26     return x & (-x);
27 }
28 //向后修改某一点的值
29 void add(int x, ll d)
30 {
31     //cout<<x<<" "<<d<<endl;
32     while(x <= n)
33     {
34         a[x] += d;
35         x += lowbit(x);
36     }
37 }
38 //向前统计[1, x]的区间和
39 ll sum(int x)
40 {
41     ll ret = 0;
42     while(x > 0)
43     {
44         ret += a[x];
45         x -= lowbit(x);
46     }
47     return ret;
48 }
49 struct node
50 {
51     int l, r;
52     int id;
53     node(){}
54     bool operator < (const node& a)const
55     {
56         return r < a.r;
57     }
58 }cnt[maxn];//离线区间
59 ll ans[maxn];
60 int main()
61 {
62     int T, cases = 0;
63     scanf("%d", &T);
64     while(T--)
65     {
66         Last.clear();
67         Mem(a);
68         int m;
69         scanf("%d", &n);
70         for(int i = 1; i <= n; i++)scanf("%lld", &c[i]);
71         scanf("%d", &m);
72         for(int i = 1; i <= m; i++)scanf("%d%d", &cnt[i].l, &cnt[i].r), cnt[i].id = i;
73         sort(cnt + 1, cnt + 1 + m);
74         int pre = 1;
75         for(int i = 1; i <= m; i++)
76         {
77             for(int j = pre; j <= cnt[i].r; j++)
78             {
79                 if(Last[c[j]])//之前出现过
80                 {
81                     add(Last[c[j]], -c[j]);
82                 }
83                 add(j, c[j]);
84                 Last[c[j]] = j;
85             }
86             pre = cnt[i].r + 1;
87             ans[cnt[i].id] = sum(cnt[i].r) - sum(cnt[i].l - 1);
88         }
89         for(int i = 1; i <= m; i++)printf("%lld\n", ans[i]);
90     }
91     return 0;
92 }

 

posted @ 2018-08-31 15:02  _努力努力再努力x  阅读(149)  评论(0编辑  收藏  举报