目录
[SDOI2009]HH的项链:
题目大意:
思路解析:
这道题的难点是,如果 l1 -- r1 这个区间有四个不同的贝壳, l2 -- r2 这个区间有3个不同的贝壳,我们并不能得到 l1 -- r2 这个区间有7个不同的贝壳,因为可能这两个区间有相同的贝壳。
但是如果我们把相同的贝壳让最后出现的这个贝壳贡献1的答案,其余相同贝壳不贡献答案,那么可能会引出 其他问题。例如:
如果考虑矩形这个区间答案为1,但实际为2。但可以发现如果我们固定右端点, 只修改右端点以前的答案,那么这个区间的任何查询都是对的。例如:
可以发现在 1 -4, 2-4, 3-4这样的区间下一定是对的,那么这里就可以引出离线操作,即我们先记录有哪些查询的右端点属于 ai这个端点,这样枚举右端点,并对右端点之前的答案进行修改后,修改完成后,使用树状数组区间查询答案即可。
代码实现:
import java.io.*;
import java.util.*;
public class Main {
static long mod = 998244353;
static int MAXN = 200005;
static int[] a = new int[MAXN];
static int[] t = new int[MAXN];
static Vector<Node>[] g;
public static void main(String[] args) throws IOException {
int n = input.nextInt();
g = new Vector[n+1];
int[] b = new int[n+1];
for (int i = 1; i <= n; i++) {
b[i] = input.nextInt();
g[i] = new Vector<>();
}
int q = input.nextInt();
for (int i = 0; i < q; i++) {
int l = input.nextInt();
int r = input.nextInt();
g[r].add(new Node(i, l));
}
int[] ans = new int[q];
int[] pre = new int[1000005];
for (int i = 1; i <= n; i++) {
if (pre[b[i]] != 0){
update(pre[b[i]], -1, n);
a[pre[b[i]]]--;
pre[b[i]] = i;
update(i,1,n);
a[i]++;
}else {
update(i,1,n);
a[i]++;
pre[b[i]] = i;
}
for (int j = 0; j < g[i].size(); j++) {
Node cur = g[i].get(j);
ans[cur.id] = sum(cur.l, i, n);
}
}
for (int i = 0; i < q; i++) {
out.println(ans[i]);
}
out.flush();
out.close();
br.close();
}
public static int lowbit(int x){
return x & (-x);
}
public static void update(int x, int val, int n){
for (int i = x; i <= n; i+=lowbit(i)) {
t[i] += val;
}
}
public static int sum(int l, int r, int n){
int sum = 0;
while (l <= r){
sum += a[r];
r--;
while (r - lowbit(r) >= l){
sum += t[r];
r -= lowbit(r);
}
}
return sum;
}
public static class Node{
int id;
int l;
public Node(int id, int l){
this.id = id;
this.l = l;
}
}
static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
static Input input = new Input(System.in);
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public char[] nextChars(){return next().toCharArray();}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
}
}