题目链接:http://acm.zzu.edu.cn:8000/problem.php?id=10508

题目大意:给定一个序列,长度为N,每次询问为一组区间[Li,Ri],输出Li到Ri中出现恰好两次的不同数的个数. N,M<=2*10^5,序列中元素<=10^9

解题思路:考虑用树状数组解决(大概是一种类型的题目)。树状数组一般用来快速计算更新(logN)前缀和,而对于本题来说,出现次数显然不能单纯随意相加相减,另外,对于右区间靠前的查询来说,对其查询之后后面的数据更新是不会再影响到它的,因此可以离线处理,并且需要在更新的时候针对重复元素进行一些处理。

首先考虑一个元素在序列中不同位置重复出现的情况,如下:

_ x _ x _ x _ x _ x _ (下划线表示出现了若干与x不相同的数字)

从前到后给每个x编号1,2,3,4,5,下面看一下从前到后扫面到这五个位置时如何更新(其中a,b等字母表示这个位置应当具有的值):

  _ x _ x _ x _ x _ x _

1  0

2  a   b       那么应当有 b + a = 1, (b + a) - a = 0, 则 b = 0, a = 1

3  a   b   c       那么应当有 c + b + a = 0, (c + b + a) - (b + a) = 0, (c + b + a) - a = 1, 则 c = 0, b = 1,  a = -1.

4  a   b   c   d    那么应当有 d + c + b + a = 0, d + c + b + a - (c + b + a) = 0, (d + c + b + a) - (b + a) = 1

             (d + c + b + a) - a = 0, 则 d = 0, c = 1, b = -1, a = 0

...

即是:

  _ x _ x _ x _ x _ x _

1  0

2  1   0        

3   -1   1   0      

4  0   -1   1   0     

5  0    0   -1   1   0

然后关系就非常明显了,我们只需要记录下每个位置的数字上次出现的位置,然后 lastpos + 1,la_lastpos - 2, la_la_lastpos + 1, 即可。那么对于任意一个区间来说,由于其中每个数字都满足互相加减的条件,因此直接树状数组相加减即可。

大致过程:记录每个位置对应数字上次出现位置;将查询的区间按照有端点排序;从1~N枚举每个位置,按上述方法更新树状数组,然后计算以这个位置为右端点结束的区间的值。

代码:

 1 const int maxn = 2e5 + 10;
 2 struct node{
 3     int l, r, id;
 4     bool operator < (const node& t) const{
 5         return r < t.r;
 6     }
 7 };
 8 node range[maxn];
 9 int n, m;
10 int a[maxn], ans[maxn], bit[maxn];
11 int last[maxn];
12 map<int, int> mmp;
13
14 int lowbit(int x){
15     return x & (-x);
16 }
17 void add(int x, int v){
18     while(x <= n){
19         bit[x] += v;
20         x += lowbit(x);
21     }
22 }
23 int sum(int x){
24     int ans = 0;
25     while(x > 0){
26         ans += bit[x];
27         x -= lowbit(x);
28     }
29     return ans;
30 }
31 void solve(){
32     memset(last, 0, sizeof(last));
33     memset(bit, 0, sizeof(bit));
34     for(int i = 1; i <= n; i++){
35         last[i] = mmp[a[i]];
36         mmp[a[i]] = i;
37     }
38     sort(range + 1, range + 1 + m);
39     int ind = 1;
40     for(int i = 1; i <= n; i++){
41         if(last[i] != 0){
42             int la = last[i];
43             add(la, 1);
44             if(last[la] != 0){
45                 int lla = last[la];
46                 add(lla, -2);
47                 if(last[lla] != 0)
48                     add(last[lla], 1);
49             }
50         }
51         while(ind <= m && range[ind].r == i){
52             int tml = range[ind].l, tmr = range[ind].r;
53             ans[range[ind].id] = sum(tmr) - sum(tml - 1);
54             ind++;
55         }
56     }
57     for(int i = 1; i <= m; i++){
58         printf("%d\n", ans[i]);
59     }
60 }
61 int main(){
62     scanf("%d %d", &n, &m);
63     for(int i = 1; i <= n; i++)
64         scanf("%d", a + i);
65     for(int i = 1; i <= m; i++){
66         scanf("%d %d", &range[i].l, &range[i].r);
67         range[i].id = i;
68     }
69     solve();
70 }

题目:

10508: 数列游戏IV

Time Limit: 1 Sec  Memory Limit: 128 MB
Submit: 32  Solved: 6
[Submit][Status][Web Board]

Description

给定一个序列,长度为N,每次询问为一组区间[Li,Ri],输出Li到Ri中出现恰好两次的不同数的个数.

Input

第一行两个整数N和M,N表示序列长度,M表示询问次数.(N,M<=2*10^5)
第二行N个整数,表示序列.(序列中元素<=10^9)
以后M行,每行为Li和Ri,表示询问区间.(1<=Li<=Ri<=N)

Output

对于每组询问,输出一行一个整数,表示不相同数的个数.

Sample Input

5 1
1 2 1 1 1
1 3

Sample Output

1

HINT

Source

Raywzy

转载于:https://www.cnblogs.com/bolderic/p/7527223.html

ZZUOJ 10508: 数列游戏IV相关推荐

  1. 1345. 跳跃游戏 IV

    Powered by:NEFU AB-IN Link 文章目录 1345. 跳跃游戏 IV 题意 思路 代码 1345. 跳跃游戏 IV 题意 略 思路 先用哈希表将每个相同元素的位置记下来,每个形成 ...

  2. c++初级-卡牌游戏 IV

    卡牌游戏 IV 蒜头君在玩一种卡牌游戏,他有n张卡牌,每张卡牌上写着两个正整数 ai,bi,ai表示这张卡牌的能量值,bi表示这张卡牌的魔法值.他准备一张一张打出这 n张卡牌,每张卡牌会对敌人造成的伤 ...

  3. 【数据结构与算法】之深入解析“石子游戏IV”的求解思路与算法示例

    一.题目要求 Alice 和 Bob 两个人轮流玩一个游戏,Alice 先手. 一开始,有 n 个石子堆在一起,每个人轮流操作,正在操作的玩家可以从石子堆里拿走任意非零平方数个石子. 如果石子堆里没有 ...

  4. leetcode 1345. Jump Game IV | 1345. 跳跃游戏 IV(BFS)

    题目 https://leetcode.com/problems/jump-game-iv/ 题解 好久没做 hard 了,今天时间多,挑战一下.用 lqy 同学的话说,这题叫做 "苦难题& ...

  5. Leetcode 1345 跳跃游戏 IV

    题目 给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0). 每一步,你可以从下标 i 跳到下标: i + 1 满足:i + 1 < arr.length i - 1 满足:i ...

  6. leetcode:跳跃游戏 IV

    dijk 22/32 class Solution {public:int minJumps(vector<int>& arr) {// dijk? 最短路径?if(arr.siz ...

  7. 2022.01.21 - 215.跳跃游戏 IV

    文章目录 1. 题目 2. 思路 (1) BFS 3. 代码 1. 题目 2. 思路 (1) BFS 首先统计每个值出现的所有位置,然后从头开始广度优先搜索. 由于从头开始的步数必然是最小的,因此,先 ...

  8. LeetCode 1696. 跳跃游戏 VI(优先队列 / 单调队列)

    文章目录 1. 题目 2. 解题 2.1 贪心错误解 2.2 优先队列/单调队列 1. 题目 给你一个下标从 0 开始的整数数组 nums 和一个整数 k . 一开始你在下标 0 处.每一步,你最多可 ...

  9. LeetCode 1690. 石子游戏 VII(博弈DP)

    文章目录 1. 题目 2. 解题 1. 题目 石子游戏中,爱丽丝和鲍勃轮流进行自己的回合,爱丽丝先开始 . 有 n 块石子排成一排.每个玩家的回合中,可以从行中 移除 最左边的石头或最右边的石头,并获 ...

最新文章

  1. idea的debug调试
  2. 译: 3. RabbitMQ Spring AMQP 之 Publish/Subscribe 发布和订阅
  3. ES6 WeakSet数据结构 与Set十分相似
  4. 看技术笔记,提高嵌入式基础
  5. 告别 ROR windows 部署的噩梦-在 windows 上面 使用 Apache 部署 Ruby On Rails
  6. P2574 XOR的艺术
  7. Oracle遇到的一些坑
  8. 写出好的 commit message
  9. c++ opencv mat_OpenCV计算机视觉-Core组件(一)
  10. 【Axure图标库】Axure彩色长阴影图标库910+ 方与圆二合一
  11. activex与matlab,在MATLAB图形用户界面设计中使用ActiveX控件
  12. 网页保存到mysql数据库_把网页数据保存到数据库
  13. 微软Google人才战主角首次开口:Google让我震撼(转)
  14. 记一次简单线上比赛--CTF(初级)
  15. 自己实现一个简单的数据库
  16. 沈阳城市学院计算机,喜讯:沈阳城市学院21个代表队在2019全国计算机大赛中全部获奖...
  17. Sophus库(Linux下)的安装(模板类.hpp,非模板类.h)
  18. 原生js 调用电脑摄像头完成拍照
  19. .net core 中使用confluent kafka构建生产者
  20. Linux sed使用方法

热门文章

  1. 在C#中使用gRPC及protobuf简介
  2. CSS 伪类选择器:如何使用 CSS3 伪类
  3. 机器学习数据倾斜的解决方法_机器学习并不总是解决数据问题的方法
  4. docker安装ubuntu镜像
  5. 贷款杠杆为什么非去不可?危险比你想象的要恐怖
  6. 历史是“混合体”,也是“内幕”:说说《三国大传》
  7. linux php运行用户名和密码,Linux实例(一)使用用户名密码验证连接Linux
  8. excel 公式 单引号 concat_从Excel的数据类型说Python
  9. binaryformatter java_Java,C#使用二进制序列化、反序列化操作数据
  10. java mongo分组统计_探秘 Dubbo 的度量统计基础设施 - Dubbo Metrics