HDU 3333 Turing Tree

原题链接为:HDU-3333

题意是给一组数,给定m个区间查询,询问这个区间中不同的数的和(即所有重复出现的数只当作一个数)。

首先这是一道数据结构的题。这道题的关键在于离线化处理后用树状数组处理。把所有询问离线之后,按照右边界排序,然后依次处理。

处理的办法是依次向右扫描,假设现在扫描到i处,则首先查询i处数值d[i]之前是否出现过。若没出现过,则在树状数组中,在i处加上d[i];若出现过,假设之前出现处为j,则在树状数组中j处减去d[j],同时在i处加上d[i]。可以发现,因为i之前的所有查询均已处理过, 所以这样的处理并不会影响结果。

简单的说,思路就是用树状数组从左向右存储数,把所有数尽可能的往右存。

为了记录d[i]是否出现过,需要离线化处理。

 

代码如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 
 5 struct Query
 6 {
 7     LL l,r;
 8     bool operator < (const Query x)
 9     {
10         if(r==x.r) return l<x.l;
11         return r<x.r;
12     }
13 };
14 LL d[30010];
15 Query q[100010];
16 LL qq[100010];
17 #define MAXN 100010
18 LL n,m,tree[MAXN];
19 LL lowbit(LL x)
20 {
21     return x&(-x);
22 }
23 void add(LL k,LL num)
24 {
25     while(k<=n)
26     {
27         tree[k]+=num;
28         k+=lowbit(k);
29     }
30 }
31 LL sum(LL k)
32 {
33     LL ans=0;
34     while(k)
35     {
36         ans+=tree[k];
37         k-=lowbit(k);
38     }
39     return ans;
40 }
41 map<LL,LL> dict;
42 LL vis[30010];
43 LL ans[100010];
44 bool cmp(LL a,LL b)
45 {
46     return q[a]<q[b];
47 }
48 int main()
49 {
50 #ifdef LOCAL
51     freopen("in.txt","r",stdin);
52 #endif
53     LL t;
54     scanf("%lld",&t);
55     while(t--)
56     {
57         LL dictnum=0;
58         dict.clear();
59         scanf("%lld",&n);
60         for(LL i=1;i<=n;i++)
61         {
62             scanf("%lld",&d[i]);
63             if(!dict.count(d[i])) dict[d[i]]=++dictnum;
64         }
65         scanf("%lld",&m);
66         for(LL i=1;i<=m;i++) scanf("%lld%lld",&q[i].l,&q[i].r);
67         for(LL i=1;i<=m;i++) qq[i]=i;
68         sort(qq+1,qq+m+1,cmp);
69         q[0].r=q[0].l=0;
70         qq[0]=0;
71         memset(tree,0,sizeof(tree));
72         memset(vis,0,sizeof(vis));
73         for(LL i=1;i<=m;i++)
74         {
75             for(LL j=q[qq[i-1]].r+1;j<=q[qq[i]].r;j++)
76             {
77                 if(vis[dict[d[j]]]) add(vis[dict[d[j]]],-d[j]);
78                 add(j,d[j]);
79                 vis[dict[d[j]]]=j;
80             }
81             ans[qq[i]]=sum(q[qq[i]].r)-sum(q[qq[i]].l-1);
82         }
83         for(LL i=1;i<=m;i++) printf("%lld\n",ans[i]);
84     }
85     return 0;
86 }

 

posted @ 2017-02-04 13:27  HuaZhang  阅读(226)  评论(0编辑  收藏  举报