您的位置:首页 > 其它

主席树 找区间内不同的数

2015-04-13 21:32 148 查看
越来越觉得主席树这个东西需要意会了……太TM深奥了TAT (๑•̀ㅂ•́)و✧

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define REP(i, s, n) for(int i = s; i <= n; i ++)
#define RAP(i, n, s) for(int i = n; i >= s; i --)
using namespace std;
const int maxn = 100000 + 10;
const int maxnode = 20 * maxn;
int ls[maxnode], rs[maxnode], root[maxn], s[maxnode];
int A[maxn], num[maxn], last[maxn], from[maxn], n, Q, ms;
int find(int v){
int L = 1, R = n, M;
while(L <= R){
M = L + R >> 1;
if(num[M] < v) L = M + 1;
else R = M - 1;
}
return L;
}
void build(int x, int& y, int L, int R, int v){
s[y = ++ ms] = s[x] + 1;
if(L == R) return ;
rs[y] = rs[x]; ls[y] = ls[x];
int M = L + R >> 1;
if(v <= M) build(ls[x], ls[y], L, M, v);
else build(rs[x], rs[y], M + 1, R, v);
return ;
}
int query(int x, int& y, int L, int R, int v){
if(L == R) return s[y] - s[x]; //把数量扔回来Σ( ° △ °|||) ︴Σ( ° △ °|||) ︴Σ( ° △ °|||)︴
int M = L + R >> 1;
if(v <= M) return query(ls[x], ls[y], L, M, v);
else return (s[ls[y]] - s[ls[x]]) + query(rs[x], rs[y], M + 1, R, v); //左边的别忘加了,注意是孩子的o(* ̄3 ̄)o
}
void read(int &x){
x = 0; int sig = 1; char ch = getchar();
while(!isdigit(ch)) { if(ch == '-') sig = -1; ch = getchar(); }
while(isdigit(ch)) x = 10 * x + ch - '0', ch = getchar();
x *= sig; return ;
}
void init(){
read(n); read(Q);
REP(i, 1, n) read(A[i]), num[i] = A[i];
sort(num + 1, num + 1 + n);
REP(i, 1, n){
build(root[i - 1], root[i], 0, n, last[from[i] = find(A[i])]);//每次更新一下头,去建“尾”的主席树
last[from[i]] = i;//别忘了更新现在到哪里了
}
return ;
}
void work(){
int L, R;
while(Q --){
read(L); read(R);
printf("%d\n", query(root[L - 1], root[R], 0, n, L - 1)); //你想想啊我们要找在这个范围内最后出现在L-1里东西的数量吧?
}
return ;
}
void print(){

return ;
}
int main(){
init();
work();
print();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: