COJ 0985 WZJ的数据结构(负十五)(限定区域不同数)

传送门:http://oj.cnuschool.org.cn/oj/home/addSolution.htm?problemID=955

试题描述:

CHX有一个问题想问问大家。给你一个长度为N的数列A,请你找到两个位置L,R,使得A[L]、A[L+1]、……、A[R]中没有重复的数,输出R-L+1的最大值。

以上是附中联赛加试的一道题。WZJ觉得这道题太水了,改了改题目:

WZJ有一个问题想问问大家。给你一个长度为N的数列A,你要回答M次问题。每次问题给你两个正整数ql,qr。请你找到两个位置L、R (ql<=L<=R<=qr),使得A[L]、A[L+1]、……、A[R]中没有重复的数,输出R-L+1的最大值。

介于某些人的吐槽(不就是我嘛(⊙ ▽ ⊙)),本题不强制在线。注意范围,祝你好运!

输入:

输入第一行为两个正整数N,M。
输入第二行为N个整数Ai。
接下来M行每行两个正整数ql,qr。

输出:

对于每个问题,输出R-L+1的最大值。

输入示例:

5 3
1 2 1 3 4
1 3
2 4
2 5

输出示例:

2
3
4

其他说明:

1<=N<=200000
1<=M<=500000
1<=ql,qr<=N
-10^9<=Ai<=10^9

题解(幸好没有强制在线呀(⊙ ▽ ⊙))分治分成DP+RMQ。

我们先搞定最长不同数区间,每次来限制了就会把它砍断,对于右边的“此区间”我们预处理循环节计数再用RMQ搞定最大值,对于左区间我们二分找到编号,然后直接用L-ql出区间(这个区间一定没有重复数辣o(* ̄3 ̄)o)

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 #include <cstring>
 5 #include <cmath>
 6 #define REP(i, s, n) for(int i = s; i <= n; i ++)
 7 #define RAP(i, n, s) for(int i = n; i >= s; i --)
 8 using namespace std;
 9 const int maxn = 200000 + 10;
10 const int maxhash = 871199;
11 int n, Q, d[maxn][20], Log[maxn], dp[maxn], A[maxn], last[maxn];
12 namespace HASH{
13     int fch[maxhash], next[maxn], val[maxn], ms = 0;
14     void hash_init() { memset(fch, -1, sizeof(fch)); }
15     int find_insert(int v){
16         int id = v % maxhash;
17         if(id < 0) id += maxhash;
18         for(int i = fch[id]; i != -1; i = next[i]) if(val[i] == v) return i;
19         next[ms] = fch[id]; val[ms] = v; return fch[id] = ms ++;
20     }
21 }using namespace HASH;
22 void RMQ(){
23     Log[0] = -1; REP(i, 1, n) d[i][0] = i - dp[i] + 1, Log[i] = Log[i >> 1] + 1;//此循环节开始计数了 
24     for(int j = 1; (1 << j) <= n; j ++)
25         for(int i = 1; i + (1 << j) - 1 <= n; i ++)
26             d[i][j] = max(d[i][j - 1], d[i + (1 << (j - 1))][j - 1]);
27     return ;
28 }
29 inline void read(int &x){
30     x = 0; int sig = 1; char ch = getchar();
31     while(!isdigit(ch)) { if(ch == '-') sig = -1; ch = getchar(); }
32     while(isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
33     x *= sig; return ;
34 }
35 inline void write(int x){
36     int len = 0, buf[10];
37     while(x) buf[++ len] = x % 10, x /= 10;
38     for(int i = len; i; i --) putchar(buf[i] + '0');
39     putchar('
'); return ;
40 }
41 void init(){
42     hash_init();
43     read(n); read(Q);
44     REP(i, 1, n) read(A[i]), A[i] = find_insert(A[i]), dp[i] = max(dp[i - 1], last[A[i]] + 1), last[A[i]] = i;
45     //更新循环节的尾巴,转移十分的机智啊我都想骂人了。最后别忘了更新自己的位置 (⊙ ▽ ⊙)
46     RMQ();
47     return ;
48 }
49 int query(int L, int R) {
50     int k = Log[R - L + 1];
51     return max(d[L][k], d[R - (1 << k) + 1][k]);
52 }
53 void work(){
54     int ql, qr;
55     while(Q --){
56         read(ql); read(qr);
57         int L = ql, R = qr + 1, M;
58         while(L + 1 < R){ //这二分什么鬼?ε=ε=ε=┏(゜ロ゜;)┛ 
59             M = L + R >> 1;
60             if(dp[M] < ql) L = M;//二分找循环节 
61             else R = M ;//二分写错了?TAT 
62         }
63         print(max(L - ql + 1, query(L + 1, qr)));//拆成两段,此循环节的前段和上一个循环节的后一段(ˉ﹃ˉ) 
64     }
65     return ;
66 }
67 void print(){
68 
69     return ;
70 }
71 int main(){
72     init();
73     work();
74     print();
75     return 0;
76 }
原文地址:https://www.cnblogs.com/chxer/p/4423593.html