例题
查询区间第k大
Code POJ 3237
#include <cstdio>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn = 1e5 + 5;
const int inf = 1e9 + 1;
struct segtree{
int tot, rt[maxn];
struct node{
int lson, rson, size;
}nd[maxn*40];
void insert(int &i, int left, int rght, int x){
int j = ++tot;
int mid = (left + rght) >> 1;
nd[j] = nd[i];
nd[j].size++;
i = j;
if(left == rght) return;
if(x <= mid) insert(nd[j].lson, left, mid, x);
else insert(nd[j].rson, mid + 1, rght, x);
}
int query(int i, int j, int left, int rght, int k){
if(left == rght) return left;
int mid = (left + rght) >> 1;
if(nd[nd[j].lson].size - nd[nd[i].lson].size >= k) return query(nd[i].lson, nd[j].lson, left, mid, k);
else return query(nd[i].rson, nd[j].rson, mid + 1, rght, k - (nd[nd[j].lson].size - nd[nd[i].lson].size));
}
}st;
int n, m;
int a[maxn], b[maxn], rnk[maxn], mp[maxn];
bool cmp(int i, int j){return a[i] < a[j];}
int main(){
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= n; ++i) rnk[i] = i;
sort(rnk + 1, rnk + 1 + n, cmp);
a[0] = inf;
for(int i = 1, j = 0; i <= n; ++i){
int k = rnk[i], kk = rnk[i-1];
if(a[k] != a[kk]) b[k] = ++j;
else b[k] = j;
mp[b[k]] = a[k];
}
for(int i = 1; i <= n; ++i) st.insert(st.rt[i] = st.rt[i-1], 1, n, b[i]);
for(int i = 1; i <= m; ++i){
int x, y, k;
scanf("%d%d%d", &x, &y, &k);
printf("%d\n", mp[st.query(st.rt[x-1], st.rt[y], 1, n, k)]);
}
return 0;
}
统计区间数字种数
Solution
用一个
last
数组记录
array
中每个数字上次出现的位置,现在问题就可以转化为统计
[left,rght]
中
last
值小于
left
的个数。
用
Ti
记录
last[i]
的贡献,即在
Ti
的
pos
处插入一个
+1
标记,查询的时候在
Trght−Tleft−1
这颗线段树上查询
[0,left−1]
的标记和。
Code HDU 5790
#include <map>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef unsigned long long ull;
const int maxn = 2e6 + 5;
const ull p = 131;
int n, m;
char str[maxn];
map<ull, int> lst;
struct segtree{
int tot, rt[maxn];
struct node{
int lson, rson, sum;
}nd[maxn];
void init(){
tot = 0;
nd[0].lson = nd[0].rson = nd[0].sum = 0;
}
void insert(int &i, int left, int rght, int pos){
int j = ++tot;
nd[j] = nd[i];
nd[j].sum++;
i = j;
if(left == rght) return;
int mid = (left + rght) >> 1;
if(pos <= mid) insert(nd[j].lson, left, mid, pos);
else insert(nd[j].rson, mid + 1, rght, pos);
}
int query(int i, int j, int left, int rght, int x, int y){
if(x <= left && rght <= y) return nd[j].sum - nd[i].sum;
int mid = (left + rght) >> 1;
int lsum = 0, rsum = 0;
if(x <= mid) lsum = query(nd[i].lson, nd[j].lson, left, mid, x, y);
if(y > mid) rsum = query(nd[i].rson, nd[j].rson, mid + 1, rght, x, y);
return lsum + rsum;
}
}st;
void add(char s[], int id){
st.rt[id] = st.rt[id-1];
ull h = 0;
for(int i = 0; s[i]; ++i){
h *= p;
h += s[i];
st.insert(st.rt[id], 0, n, lst[h]);
lst[h] = id;
}
}
void work(){
st.init();
lst.clear();
for(int i = 1; i <= n; ++i){
scanf("%s", str);
add(str, i);
}
scanf("%d", &m);
for(int i = 1, Z = 0; i <= m; ++i){
int left, rght, L, R;
scanf("%d%d", &L, &R);
left = min((Z + L) % n, (Z + R) % n) + 1;
rght = max((Z + L) % n, (Z + R) % n) + 1;
printf("%d\n", Z = st.query(st.rt[left-1], st.rt[rght], 0, n, 0, left - 1));
}
}
int main(){
while(scanf("%d", &n) == 1) work();
return 0;
}