【树状数组+离线查询】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 }

时间: 2024-10-11 21:17:34

【树状数组+离线查询】HDU 3333 Turing Tree的相关文章

HDU 3333 Turing Tree 树状数组 离线查询

题意: 给你一个数列,然后有n个查询,问你给定区间中不同数字的和是多少. 思路还是比较难想的,起码对于蒟蒻我来说. 将区间按照先右端点,后左端点从小到大排序之后,对于每个查询,我只要维护每个数字出现的最后一次就可以了(这个结论稍微想一下就可以证明是正确的). 然后就是简单的点更新,区间求和问题了- #include <cstdio> #include <cstring> #include <iostream> #include <map> #include

(树状数组+离线查询)HDU 4417 - Super Mario

题意: 给定一个数列,最多10万次查询l到r不超过h的数字的个数. 分析: 唉,太菜啦. 在线做法应该比较明显,区间维护平衡树,用线段树套平衡树,或者分块套平衡树,应该都能A,但是没试过,只是BB,如有错误欢迎指正. 其实最方便的做法离线做法,太巧妙啦. 把数列按升序排列,把所有查询按h升序排列. 每次查询把比h的小的位置标记为1,查询用bit的sum(r)-sum(l-1)即可 因为都是单调的,所以很方便. 其实很多没有修改的区间问题都可以转化成离线问题. 甚至于一些带修改的题都可以离线. 这

HDU 3333 Turing Tree(树状数组离线处理)

HDU 3333 Turing Tree 题目链接 题意:给定一个数组,每次询问一个区间,求出这个区间不同数字的和 思路:树状数组离线处理,把询问按右端点判序,然后用一个map记录下每个数字最右出现的位置,因为一个数字在最右边出现,左边那些数字等于没用了,利用树状数组进行单点修改区间查询即可 代码: #include <cstdio> #include <cstring> #include <algorithm> #include <map> using n

HDU 3333 Turing Tree (离散化+离线处理+树状数组)

Problem Description After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because Turing Tree could easily have the solution. As well, wily 3xian made lots of new problems about intervals. So, today, this sick t

hdu 3333 树状数组+离线处理

http://acm.hdu.edu.cn/showproblem.php?pid=3333 不错的题,想了很久不知道怎么处理,而且答案没看懂,然后找个例子模拟下别人的代码马上懂了---以后看不懂的话就拿个例子模拟下别人的代码 举个例子:1 3 3 5 3 5 查询 a, 2 4 b, 2 5 最初是这么想的:对于a查询,倘若把第二个数第三个数变成1个3,那么到b查询,又出现了两个3,再做处理似乎还是O(n),而且如果先出现2,5查询,后出现2,4查询,那么还需要把删除的数补回来.....o(╯

HDU 4417 Super Mario ( 超级马里奥 + 主席树 + 线段树/树状数组离线处理 + 划分树 )

HDU 4417 - Super Mario ( 主席树 + 线段树/树状数组离线处理 + 划分树 ) 这道题有很多种做法,我先学习的是主席树.后面陆续补上线段树离线和划分树 题目大意就是给定一个区间给定一个数列,每次要求你查询区间[L,R]内不超过K的数的数量 主席树做法: 最基本的是静态第k大,这里是求静态的 <= K,差不多,在Query操作里面需要修改修改 先建立size棵主席树,然后询问的时候统计的是 第R棵主席树中[1,K]的数量 - 第L-1棵主席树中[1,K]的数量 注意这里下标

hdu 4368 树状数组 离线维护

http://acm.hdu.edu.cn/showproblem.php?pid=4638 Problem Description There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-1 are friends, Whose ID is i and i+1 are friends. These n men stand in line. Now we select an interv

Necklace HDU - 3874 (线段树/树状数组 + 离线处理)

Necklace HDU - 3874 Mery has a beautiful necklace. The necklace is made up of N magic balls. Each ball has a beautiful value. The balls with the same beautiful value look the same, so if two or more balls have the same beautiful value, we just count

hdu 3333 Turing Tree(线段树)

题目链接:hdu 3333 Turing Tree 题目大意:给定一个长度为N的序列,有M次查询,每次查询l,r之间元素的总和,相同元素只算一次. 解题思路:涨姿势了,线段树的一种题型,离线操作,将查询按照右区间排序,每次考虑一个询问,将mv ~ r的点全部标记为存在,并且对于每个位置i,如果A[i]在前面已经出现过了,那么将前面的那个位置减掉A[i],当前位置添加A[i],这样做维护了每个数尽量做,那么碰到查询,用sum[r] - sum[l-1]即可. #include <cstdio>