CF 351D, 离线处理+树状数组/莫队算法

颓颓颓

题目大意:给你m个区间询问,询问区间内有多少个不相同的数以及存不存在一种数字组成的数列为等差间隔的数列。

解:离线询问,不相同的数其实是老做法了,但是巧妙的是数字是否为等差间隔。我们把询问按右区间排序,可知等差间隔必然是连续的一段,那么从当前枚举点往左,合法数列必然是连续的一段,那么我们用树状数组+1-1维护区间延伸到哪里,然后询问[l,i]当中和是否为零就知道有没有符合的连续一段等差间隔数列了。

顺便这题官解是莫队,正好我也去研究一下莫队吧,现在先贴一个离线nlogn的做法,递归学会莫队后再来补充。

  1 #include <cstdio>
  2 #include <string>
  3 #include <iostream>
  4 #include <algorithm>
  5 #include <cmath>
  6 #include <cstring>
  7 #include <complex>
  8 #include <set>
  9 #include <vector>
 10 #include <map>
 11 #include <queue>
 12 #include <deque>
 13 #include <ctime>
 14
 15 using namespace std;
 16
 17 const double EPS = 1e-8;
 18
 19 #define ABS(x) ((x)<0?(-(x)):(x))
 20 #define SQR(x) ((x)*(x))
 21 #define MIN(a,b) ((a)<(b)?(a):(b))
 22 #define MAX(a,b) ((a)>(b)?(a):(b))
 23
 24 #define LSON(x) ((x)<<1)
 25 #define RSON(x) (((x)<<1)+1)
 26 #define LOWBIT(x) ((x)&(-(x)))
 27 #define MAXS 1111
 28 #define MAXN 222222
 29 #define VOIDPOINT 0
 30 #define LL long long
 31 #define OO 214748364
 32 #define INF 0x3f3f3f3f
 33 #define MP(x,y) make_pair(x,y)
 34
 35 struct TreeArray{
 36     int tree[MAXN], n;
 37     void clear(int nn = MAXN-10) {
 38         n = nn;
 39         memset(tree, 0, sizeof(tree[0])*(n+10));
 40     }
 41     void add(int x, int num = 1) {
 42         if (x < 1) return ;
 43         while (x <= n) {
 44             tree[x] += num;
 45             x += LOWBIT(x);
 46         }
 47     }
 48     int get(int x) {
 49         int res = 0;
 50         while (x > 0) {
 51             res += tree[x];
 52             x -= LOWBIT(x);
 53         }
 54         return res;
 55     }
 56
 57 } color, sl;
 58
 59 struct query{
 60     int l, r, id;
 61     query(int a = 0, int b = 0, int c = 0): l(a), r(b), id(c) {}
 62     bool operator < (const query &rhs) const {
 63         return r < rhs.r;
 64     }
 65 } q[MAXN];
 66
 67 int a[MAXN], n, m, ans[MAXN];
 68 int pre[MAXN], f[MAXN], last[MAXN];
 69
 70 int main() {
 71 //    freopen("test.txt", "r", stdin);
 72
 73
 74     color.clear(); sl.clear();
 75 //    memset(pre, -1, sizeof(pre));
 76     memset(last, -1, sizeof(last));
 77
 78     scanf("%d", &n);
 79     for (int i = 1; i <= n; ++i) {
 80 //        cout << i << endl;
 81         scanf("%d", &a[i]);
 82         pre[i] = last[a[i]];
 83         if (pre[i] != -1) {
 84             if (pre[pre[i]] != -1) {
 85                 if (i - pre[i] == pre[i] - pre[pre[i]]) f[i] = f[pre[i]];
 86                 else f[i] = pre[i];
 87             } else
 88                 f[i] = f[pre[i]];
 89         } else
 90             f[i] = -1;
 91         last[a[i]] = i;
 92     }
 93     scanf("%d", &m);
 94     for (int i = 0; i < m; ++i) {
 95         int x, y; scanf("%d%d", &x, &y);
 96         q[i] = query(x, y, i);
 97     }
 98     sort(q, q+m);
 99
100
101     for (int i = 1, j = 0; i <= n; ++i) {
102         color.add(i);
103         if (pre[i] != -1) color.add(pre[i], -1);
104
105         if (pre[i] != -1) {
106             if (f[i] == f[pre[i]]) {
107                 sl.add(pre[i], -1); sl.add(i);
108             } else {
109                 sl.add(f[pre[i]] == -1 ? -1: pre[f[pre[i]]], 1); sl.add(pre[i], -1);
110                 sl.add(pre[pre[i]], -1); sl.add(i, 1);
111             }
112         } else {
113             sl.add(i);
114         }
115
116         while (j < m && q[j].r == i) {
117 //            cout << i << ‘ ‘<< q[j].l << ‘ ‘ << q[j].r << endl;
118
119 //            cout <<  (sl.get(q[j].r) - sl.get(q[j].l-1)) << endl;
120 //            cout << color.get(q[j].r) <<‘ ‘<< color.get(q[j].l-1) << endl;
121
122             ans[q[j].id] = color.get(q[j].r) - color.get(q[j].l-1) + (sl.get(q[j].r) - sl.get(q[j].l-1) == 0);
123             ++j;
124             if (i == -31) {
125                 cout << i << endl;
126                 for (int k = 1; k <= i; ++k) cout << color.get(k) <<‘ ‘; cout << endl;
127                 for (int k = 1; k <= i; ++k) cout << a[k] <<‘ ‘; cout << endl;
128                 for (int k = 1; k <= i; ++k) cout << sl.get(k) - sl.get(k-1) << ‘ ‘; cout << endl;
129             }
130         }
131     }
132
133     for (int i = 0; i < m; ++i) printf("%d\n", ans[i]);
134
135     return 0;
136 }

CF 351D

时间: 2024-10-10 05:18:29

CF 351D, 离线处理+树状数组/莫队算法的相关文章

BZOJ 1878 SDOI2009 HH的项链 树状数组/莫队算法

题目大意:给定一个序列.求一个区间内有多少个不同的数 正解是树状数组 将全部区间依照左端点排序 然后每次仅仅统计左端点開始的每种颜色的第一个数即可了 用树状数组维护 我写的是莫队算法 莫队明显能搞 m√m明显慢了点可是还是能接受的一个复杂度 一開始离散化数组开小了各种秒RE-- 跪了 #include<cmath> #include<cstdio> #include<cstring> #include<iostream> #include<algori

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

【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 题解 单调栈+离线+扫描线+树状数组区间修改 首先把使用单调栈找出每个

SPOJ - DQUERY: D-query 离线处理 + 树状数组

题目链接:https://vjudge.net/problem/SPOJ-DQUERY 题意:给定数字序列,求任意区间内的不同数字的个数 解法:用树状数组维护 1 ~ i 的区间内不同数字个数的前缀和,首要解决的问题就是同一区间内相同数字统计时相互影响的问题,解决方法如下:离线存储查询的区间,对查询区间按照左端点排序,这样可以优先处理左边的           元素:然后预处理出每一元素下一跳到相同元素的 nxt[]; 这样随着坐标轴指针 l 的移动,l 左边的元素将不会产生任何影响,因为所产生

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

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3333 题目大意: 给出一数组,以及m个查询区间,每次查询该区间不同数字的和.相同数字只加一次. 解题思路: 离线区间,按照区间右端点进行排序. 这样可以从左到右扫一遍,用尺取法一个一个将数字放入树状数组中. 如果这个数字已经在树状数组里面,记录之前的下标,再从树状数组中删去之前下标的这个数字,在当前下标添加该数字.这样可以保证每一步操作,都会使得树状数组中没有重复元素.这样可以直接用树状数组求不同

codeforces 703D Mishka and Interesting sum 偶数亦或 离线+前缀树状数组

题目传送门 题目大意:给出n个数字,m次区间询问,每一次区间询问都是询问 l 到 r 之间出现次数为偶数的数 的亦或和. 思路:偶数个相同数字亦或得到0,奇数个亦或得到本身,那么如果把一段区间暴力亦或,得到的其实就是出现次数为奇数的数字的亦或和,所以我们希望这段区间内的所有数字出现次数都+1,使奇偶性互换. 我们先处理出前缀的亦或和,这样可以得到次数为奇数的亦或和. 接下来的问题就是要改变一段区间的奇偶性了,也就是说,这个问题其实就转化成了如何求一段区间出现的所有数字(无重复). 这里我学到的是

CCPC河南省赛B-树上逆序对| 离线处理|树状数组 + 线段树维护逆序对 + dfs序 + 离散化

B题地址:树上逆序对 有两个思路 方法一:线段树离线 + 树状数组或者线段树维护区间和 0:离散化,离线存储输入的operation操作序列. ①:先线段树在dfs序上离线处理好整一棵树:在dfs序上先查询"加入当前结点的逆序对权值和"并记录,再加入当前这个节点:dfs完毕后,就已经记录好每个结点的dfs序出入时间戳(转化成区间问题了)和每个 ②:使用树状数组或者新的线段树在dfs序上插入逆序对权值 为什么能这样呢?因为dfs序维护了每个结点遍历的顺序,每个结点的dfs序时间戳肯定比它

CF 313 DIV2 B 树状数组

http://codeforces.com/contest/313/problem/B 题目大意 给一个区间,问你这个区间里面有几个连续相同的字符. 思路: 表示个人用树状数组来写的...了解了树状数组的本质就行了. 当然用sum[r]-sum[l]也是可以的

cf 830B - Cards Sorting 树状数组

B. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard input output standard output Vasily has a deck of cards consisting of n cards. There is an integer on each of the cards, this integer is between 1 and 10