主席树 找区间内不同的数

越来越觉得主席树这个东西需要意会了……太TM深奥了TAT (?•??•?)??

 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 = 100000 + 10;
10 const int maxnode = 20 * maxn;
11 int ls[maxnode], rs[maxnode], root[maxn], s[maxnode];
12 int A[maxn], num[maxn], last[maxn], from[maxn], n, Q, ms;
13 int find(int v){
14     int L = 1, R = n, M;
15     while(L <= R){
16         M = L + R >> 1;
17         if(num[M] < v) L = M + 1;
18         else R = M - 1;
19     }
20     return L;
21 }
22 void build(int x, int& y, int L, int R, int v){
23     s[y = ++ ms] = s[x] + 1;
24     if(L == R) return ;
25     rs[y] = rs[x]; ls[y] = ls[x];
26     int M = L + R >> 1;
27     if(v <= M) build(ls[x], ls[y], L, M, v);
28     else build(rs[x], rs[y], M + 1, R, v);
29     return ;
30 }
31 int query(int x, int& y, int L, int R, int v){
32     if(L == R) return s[y] - s[x]; //把数量扔回来Σ( ° △ °|||) ︴Σ( ° △ °|||) ︴Σ( ° △ °|||)︴
33     int M = L + R >> 1;
34     if(v <= M) return query(ls[x], ls[y], L, M, v);
35     else return (s[ls[y]] - s[ls[x]]) + query(rs[x], rs[y], M + 1, R, v); //左边的别忘加了,注意是孩子的o(* ̄3 ̄)o
36 }
37 void read(int &x){
38     x = 0; int sig = 1; char ch = getchar();
39     while(!isdigit(ch)) { if(ch == ‘-‘) sig = -1; ch = getchar(); }
40     while(isdigit(ch)) x = 10 * x + ch - ‘0‘, ch = getchar();
41     x *= sig; return ;
42 }
43 void init(){
44     read(n); read(Q);
45     REP(i, 1, n) read(A[i]), num[i] = A[i];
46     sort(num + 1, num + 1 + n);
47     REP(i, 1, n){
48         build(root[i - 1], root[i], 0, n, last[from[i] = find(A[i])]);//每次更新一下头,去建“尾”的主席树
49         last[from[i]] = i;//别忘了更新现在到哪里了
50     }
51     return ;
52 }
53 void work(){
54     int L, R;
55     while(Q --){
56         read(L); read(R);
57         printf("%d\n", query(root[L - 1], root[R], 0, n, L - 1)); //你想想啊我们要找在这个范围内最后出现在L-1里东西的数量吧?
58     }
59     return ;
60 }
61 void print(){
62
63     return ;
64 }
65 int main(){
66     init();
67     work();
68     print();
69     return 0;
70 }
时间: 2024-08-27 22:48:08

主席树 找区间内不同的数的相关文章

SPOJ 3267 D-query(离散化+主席树求区间内不同数的个数)

DQUERY - D-query #sorting #tree English Vietnamese Given a sequence of n numbers a1, a2, ..., an and a number of d-queries. A d-query is a pair (i, j) (1 ≤ i ≤ j ≤ n). For each d-query (i, j), you have to return the number of distinct elements in the

HDU 4417 Super Mario(主席树求区间内的区间查询+离散化)

Super Mario Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5101    Accepted Submission(s): 2339 Problem Description Mario is world-famous plumber. His “burly” figure and amazing jumping abilit

HDU 5919 - Sequence II (2016CCPC长春) 主席树 (区间第K小+区间不同值个数)

HDU 5919 题意: 动态处理一个序列的区间问题,对于一个给定序列,每次输入区间的左端点和右端点,输出这个区间中:每个数字第一次出现的位子留下, 输出这些位子中最中间的那个,就是(len+1)/2那个. 思路: 主席树操作,这里的思路是从n到1开始建树.其他就是主席树查询区间第K小,计算区间不同值个数. #include <algorithm> #include <iterator> #include <iostream> #include <cstring&

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

【大杀器】利用划分树秒杀区间内第k大的数

最近看了一道题,大概就是给出一个序列,不断询问其子区间内第k大的数,下面是个截图 绕了一圈没找到中文版题目,if(你是大佬) then 去看截图:else{我来解释:给出一个整数n,和一个整数m,分别表示序列元素个数和询问次数,然后输入n个数和m个询问,每个询问包含3个数,分别是区间起止点(l和r)和k,求出区间内第k大的数并输出:}这是一道很简单的模板题,怎么解决呢?小编最初想到的是打暴力,正所谓暴力出奇迹,说不定可以成功,反正不会优化,先试试吧,直接把规定区间[l,r]排一次序了,然后在查找

主席树(区间第k小的数)

题目链接: https://www.luogu.org/problem/P3834 首先要离散化,然后主席树模板. 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mid (l+r)/2 5 using namespace std; 6 7 const int N = 200010; 8 int n, q, m, cnt = 0; 9 int a[N], b[N], T[N];

[知识点]主席树入门 区间k值

入坑主席树主要是因为昨天考试的后两道题不可改2333 而且觉得这个还挺有用,于是果断入坑 不过蒟蒻的我只是在上午看了看大概思路,下午开的运动会没时间码,于是晚上码了出来.但是目前只会无修改的区间K值问题,加上又比较抽象,思路屡了半天才刚刚醒悟,于是写下来记录一下. 不扯那么多辣鸡套路,直接说思路打法(以k小值为例): 我们先要以权值建一颗线段树,然后每个节点记录的是这个节点管辖的范围内数列中数的个数. 我们需要建好多好多线段树.简单来讲呢,就是[1,1],[1,2]···[1,n]这么多颗,每棵

主席树|求区间第k小模板

主席树 学了主席树,用来求区间上的第k小 写一下自己整理后的模板 求区间第k小 #include<bits/stdc++.h> using namespace std; //求区间第k小 const int maxn = 500010; struct node{ int v,lc,rc; }T[maxn * 21]; int n,m; int root[maxn]; int e; void insert(int pre,int cur,int pos,int l,int r){ if(l ==

POJ2104-- K-th Number(主席树静态区间第k大)

[转载]一篇还算可以的文章,关于可持久化线段树http://finaltheory.info/?p=249 无修改的区间第K大 我们先考虑简化的问题:我们要询问整个区间内的第K大.这样我们对值域建线段树,每个节点记录这个区间所包含的元素个数,建树和查询时的区间范围用递归参数传递,然后用二叉查找树的询问方式即可:即如果左边元素个数sum>=K,递归查找左子树第K大,否则递归查找右子树第K – sum大,直到返回叶子的值. 现在我们要回答对于区间[l, r]的第K大询问.如果我们能够得到一个插入原序