bzoj 3489 A simple rmq problem - 线段树

Description

因为是OJ上的题,就简单点好了。给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出0。我会采取一些措施强制在线。

Input

第一行为两个整数N,M。M是询问数,N是序列的长度(N<=100000,M<=200000)

第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N

再下面M行,每行两个整数x,y,

询问区间[l,r]由下列规则产生(OIER都知道是怎样的吧>_<):

l=min((x+lastans)mod n+1,(y+lastans)mod n+1);

r=max((x+lastans)mod n+1,(y+lastans)mod n+1);

Lastans表示上一个询问的答案,一开始lastans为0

Output

一共M行,每行给出每个询问的答案。

Sample Input

10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9

Sample Output

4
10
10
0
0
10
0
4
0
4

HINT

注意出题人为了方便,input的第二行最后多了个空格。

2015.6.24新加数据一组,2016.7.9放至40S,600M,但未重测

Source

by zhzqkkk



  题目大意 询问区间内只出现1次数的最大值。强制在线。

  考虑每位置上的数会对哪些询问作出贡献。

  显然要让位置i对答案产生贡献询问的区间需要满足 pre[i] < l <= i 并且 i <= r < suf[i] 。

  那么就可以将每个询问(l, r)看成二维平面内的一个点。

  这样的话,每个位置对答案的贡献就可以通过2维线段树来进行维护。

  为了防止MLE,所以采取标记永久化的方案。但是注意修改操作是和线段树维护的信息取max。

Code

  1 /**
  2  * bzoj
  3  * Problem#3489
  4  * Accepted
  5  * Time: 21836ms
  6  * Memory: 227780k
  7  */
  8 #include <bits/stdc++.h>
  9 using namespace std;
 10 typedef bool boolean;
 11
 12 typedef class SegTreeNode {
 13     public:
 14         SegTreeNode* val;
 15         SegTreeNode *l, *r;
 16
 17         SegTreeNode(int val = 0):val((SegTreeNode*)val) {        }
 18         SegTreeNode(int val, SegTreeNode* org):val((SegTreeNode*)val) {
 19             l = r = org;
 20         }
 21
 22         int intvalue() {
 23             return (int)val;
 24         }
 25
 26         SegTreeNode*& pnodeval() {
 27             return val;
 28         }
 29
 30         void set(int x) {
 31             val = (SegTreeNode*)x;
 32         }
 33 }SegTreeNode;
 34
 35 #define PLimit 10000000
 36
 37 //int alloced = 0;
 38 SegTreeNode pool[PLimit];
 39 SegTreeNode null = SegTreeNode(0, &null);
 40 SegTreeNode* top = pool;
 41
 42 SegTreeNode* newnode() {
 43 //    alloced++;
 44     if(top >= pool + PLimit)
 45         return new SegTreeNode(0, &null);
 46     *top = SegTreeNode(0, &null);
 47     return top++;
 48 }
 49
 50 typedef class SegTree {
 51     public:
 52         int n;
 53         SegTreeNode* rt;
 54
 55         SegTree() {        }
 56         SegTree(int n):n(n), rt(newnode()) {        }
 57
 58         void update2(SegTreeNode*& node, int l, int r, int ql, int qr, int val) {
 59             if(node == &null || node == NULL)
 60                 node = newnode();
 61             if(l == ql && r == qr) {
 62                 if(val > node->intvalue())
 63                     node->set(val);
 64                 return;
 65             }
 66             int mid = (l + r) >> 1;
 67             if(ql <= mid)
 68                 update2(node->l, l, mid, ql, (qr > mid) ? (mid) : (qr), val);
 69             if(qr > mid)
 70                 update2(node->r, mid + 1, r, (ql > mid) ? (ql) : (mid + 1), qr, val);
 71         }
 72
 73         void update(SegTreeNode*& node, int l, int r, int ql, int qr, int qx, int qy, int val) {
 74             if(node == &null)
 75                 node = newnode();
 76             if(l == ql && r == qr) {
 77                 update2(node->pnodeval(), 1, n, qx, qy, val);
 78                 return;
 79             }
 80             int mid = (l + r) >> 1;
 81             if(ql <= mid)
 82                 update(node->l, l, mid, ql, (qr > mid) ? (mid) : (qr), qx, qy, val);
 83             if(qr > mid)
 84                 update(node->r, mid + 1, r, (ql > mid) ? (ql) : (mid + 1), qr, qx, qy, val);
 85         }
 86
 87         int query2(SegTreeNode*& node, int l, int r, int idx) {
 88             if(node == NULL || node == &null)
 89                 return 0;
 90             if(l == idx && r == idx)
 91                 return node->intvalue();
 92             int mid = (l + r) >> 1, rt = node->intvalue(), cmp = 0;
 93             if(idx <= mid)
 94                 cmp = query2(node->l, l, mid, idx);
 95             else
 96                 cmp = query2(node->r, mid + 1, r, idx);
 97             return (cmp > rt) ? (cmp) : (rt);
 98         }
 99
100         int query(SegTreeNode*& node, int l, int r, int idx, int bidx) {
101             if(node == &null)
102                 return 0;
103             if(l == idx && r == idx)
104                 return query2(node->pnodeval(), 1, n, bidx);
105             int mid = (l + r) >> 1, rt = query2(node->pnodeval(), 1, n, bidx), cmp;
106             if(idx <= mid)
107                 cmp = query(node->l, l, mid, idx, bidx);
108             else
109                 cmp = query(node->r, mid + 1, r, idx, bidx);
110             return (cmp > rt) ? (cmp) : (rt);
111         }
112 }SegTree;
113
114 int n, m;
115 int *ar;
116 int *pre, *suf;
117 int *head;
118 SegTree st;
119
120 inline void init() {
121     scanf("%d%d", &n, &m);
122     st = SegTree(n);
123     ar = new int[(n + 1)];
124     pre = new int[(n + 1)];
125     suf = new int[(n + 1)];
126     head = new int[(n + 1)];
127     for(int i = 1; i <= n; i++)
128         scanf("%d", ar + i);
129 }
130
131 inline void solve() {
132     memset(head, 0, sizeof(int) * (n + 1));
133     for(int i = 1; i <= n; i++)
134         pre[i] = head[ar[i]], head[ar[i]] = i;
135     fill(head, head + n + 1, n + 1);
136     for(int i = n; i; i--)
137         suf[i] = head[ar[i]], head[ar[i]] = i;
138
139     for(int i = 1; i <= n; i++)
140         st.update(st.rt, 1, n, pre[i] + 1, i, i, suf[i] - 1, ar[i]);//, fprintf(stderr, "%d: Memory Usage: %d (%d nodes)\n", i, alloced * sizeof(SegTreeNode), alloced);
141     int lastans = 0, x, y;
142     while(m--) {
143         scanf("%d%d", &x, &y);
144         x = (x + lastans) % n + 1;
145         y = (y + lastans) % n + 1;
146         if(x > y)    swap(x, y);
147         lastans = st.query(st.rt, 1, n, x, y);
148         printf("%d\n", lastans);
149     }
150 }
151
152 int main() {
153     init();
154     solve();
155     return 0;
156 }
时间: 2024-10-06 15:32:23

bzoj 3489 A simple rmq problem - 线段树的相关文章

bzoj 3489 A simple rmq problem —— 主席树套线段树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3489 题解:http://www.itdaan.com/blog/2017/11/24/9bc46b690756fe252e17fc3ca90aa01.html 在我挣扎一下午时 Narh 早就A了... 于是看看有何不同,发现 add  和 insert 中必须把 ls[x] = ls[y] , rs[x] = rs[y] 写在前面,而不能是修改 rs 则在那里单写一个 ls[x] =

[BZOJ 3489] A simple rmq problem 【可持久化树套树】

题目链接:BZOJ - 3489 题目分析 “因为是OJ上的题,就简单点好了.”——出题人 真的..好..简单... 首先,我们求出每个数的前一个与它相同的数的位置,即 prev[i] ,如果前面没有相同的数,prev[i] = 0. 再求出每个数的后一个与它相同的数的位置,即 next[i], 如果后面没有相同的数,next[i] = n + 1. 这样,对于 l > prev[i], r < next[i] 的区间,i 这个数在区间中至多出现一次. 那么我们要求的就是:符合 prev[i]

BZOJ 3489 A simple rmq problem 可持久化树套树

题目大意:给定一个序列,多次询问某一区间中出现且仅出现一次的最大的数 令第i个数左侧第一个与这个数相同的数为last[i] 右侧第一个与这个相同的数为next[i] 那么一个数a[i]在区间内出现一次当且仅当last[i]<l&&next[i]>r&&l<=i<=r 于是我们将元素按照last[i]排序并构建可持久化线段树 令pos为满足last[i]<l的最大的i 每次查询我要查询的是第pos个版本的线段树内所有next[i]>r的数中

bzoj 3489: A simple rmq problem

1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define M 200009 5 using namespace std; 6 struct A 7 { 8 int d[3],mx[3],mn[3],l,r,v,mx1; 9 }a[M]; 10 int n,b[M],v[M],N,ans,root,m; 11 bool cmp(A a1,A a2) 12 { 13 return a1.d

ZOJ 3686 A Simple Tree Problem(线段树)

A Simple Tree Problem Time Limit: 3 Seconds      Memory Limit: 65536 KB Given a rooted tree, each node has a boolean (0 or 1) labeled on it. Initially, all the labels are 0. We define this kind of operation: given a subtree, negate all its labels. An

hdu 4973 A simple simulation problem.(线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=4973 有两种操作 D l r 将[l,r]区间翻倍 Q l r询问[l,r]中相同数字出现的最多次数 比赛的时候脑子太乱了,没有想到怎么做.发现每次翻倍序列的长度都在变化,区间对应的数也在变,没有思路. 但是静下心来想一想,思路还是挺清晰的. 无论怎么翻倍,序列中的数都是连续的,范围是1~n.可以拿一个数组来记录每个数出现的次数,当更新或询问区间[l,r]时,可以利用其前缀和找到区间[l,r]对应的数字分别是

bzoj 3585: mex &amp;&amp; 3339: Rmq Problem -- 主席树

3585: mex Time Limit: 20 Sec  Memory Limit: 128 MB Description 有一个长度为n的数组{a1,a2,...,an}.m次询问,每次询问一个区间内最小没有出现过的自然数. Input 第一行n,m. 第二行为n个数. 从第三行开始,每行一个询问l,r. Output 一行一个数,表示每个询问的答案. Sample Input 5 5 2 1 0 2 1 3 3 2 3 2 4 1 2 3 5 Sample Output 1 2 3 0 3

HDU4973A simple simulation problem.(线段树,区间更新)

A simple simulation problem. Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 330    Accepted Submission(s): 132 Problem Description There are n types of cells in the lab, numbered from 1 to n.

HDU-4937-A simple simulation problem.(线段树)

Problem Description There are n types of cells in the lab, numbered from 1 to n. These cells are put in a queue, the i-th cell belongs to type i. Each time I can use mitogen to double the cells in the interval [l, r]. For instance, the original queue