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 }

原文地址:https://www.cnblogs.com/fzl194/p/9565885.html

时间: 2024-10-12 19:18:09

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

【bzoj4540】[Hnoi2016]序列 单调栈+离线+扫描线+树状数组区间修改

题目描述 给出一个序列,多次询问一个区间的所有子区间最小值之和. 输入 输入文件的第一行包含两个整数n和q,分别代表序列长度和询问数.接下来一行,包含n个整数,以空格隔开,第i个整数为ai,即序列第i个元素的值.接下来q行,每行包含两个整数l和r,代表一次询问. 输出 对于每次询问,输出一行,代表询问的答案. 样例输入 5 5 5 2 4 1 3 1 5 1 3 2 4 3 5 2 5 样例输出 28 17 11 11 17 题解 单调栈+离线+扫描线+树状数组区间修改 首先把使用单调栈找出每个

hdu 1116 敌兵布阵(树状数组区间求最值)

题意: 给出一行数字,然后可以修改其中第i个数字,并且可以询问第i至第j个数字的和(i <= j). 输入: 首行输入一个t,表示共有t组数据. 接下来每行首行输入一个整数n,表示共有n个数字. 接下来每行首先输入一个字符串,如果是”Add”,接下来是两个整数a,b,表示给第i个数增加b.如果是”Query”,接下来是两个整数a,b,表示查询从第i个数到第j个数之间的和.如果是”End”,表示这组数据结束. 输出: 每组数据首先输出”Case X: ”,其中X表示第x组数. 每次查询,输出计算结

hdu 1754 I Hate It(树状数组区间求最值)2007省赛集训队练习赛(6)_linle专场

题意: 输入一行数字,查询第i个数到第j个数之间的最大值.可以修改其中的某个数的值. 输入: 包含多组输入数据. 每组输入首行两个整数n,m.表示共有n个数,m次操作. 接下来一行包含n个整数. 接下来m行,每行包含一个字母s,两个整数a,b. 当s为’Q’,表示查询第a个数到第b个数之间的最大值. 当s为’U’,表示将第a个数更改为b. 输出: 每次查询输出一个结果,每次输出占一行. 题解: 点修改区间求最值,可以用树状数组模板. 具体见代码—— 1 #include <cstdio> 2

HDU 3333 Turing Tree (离线询问+线段树)

题目地址:HDU 3333 将询问离线保存下来,然后将数组的点离散化,记录每个值上一次出现的位置.然后枚举数组的数,若当前枚举的数前面出现过,那么就删掉前面出现过的那个位置上的数,更新当前这个位置上的数,然后那些所有询问的右端点为当前位置的就可以通过查询来得到结果了. 更新与查询用线段树来优化. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #

HDU - 1556 Color the ball (一维树状数组 + 区间修改 + 单点求值)

HDU - 1556 Color the ball Time Limit: 3000MS   Memory Limit: 32768KB   64bit IO Format: %I64d & %I64u Submit Status Description N个气球排成一排,从左到右依次编号为1,2,3....N.每次给定2个整数a b(a <= b),lele便为骑上他的"小飞鸽"牌电动车从气球a开始到气球b依次给每个气球涂一次颜色.但是N次以后lele已经忘记了第I个气

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

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

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 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>

【POJ 3321】 Apple Tree (dfs重标号设区间+树状数组求和)

[POJ 3321] Apple Tree (dfs重标号设区间+树状数组求和) Apple Tree Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 21966   Accepted: 6654 Description There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the tree. K