时间限制:1.00s
内存限制:125.00MB
OJ:洛谷P1533
题目背景
小卡由于公务需要出差,将新家中的狗狗们托付给朋友嘉嘉,但是嘉嘉是一个很懒的人,他才没那么多时间帮小卡喂狗狗。
题目描述
小卡家有N
只狗,由于品种、年龄不同,每一只狗都有一个不同的漂亮值。漂亮值与漂亮的程度成反比(漂亮值越低越漂亮),吃饭时,狗狗们会按顺序站成一排等着主人给食物。
可是嘉嘉真的很懒,他才不肯喂这么多狗呢,这多浪费时间啊,于是他每次就只给第i
只到第j
只狗中第k
漂亮的狗狗喂食(好狠心的人啊)。而且为了保证某一只狗狗不会被喂太多次,他喂的每个区间(i,j)
不互相包含。
输入格式
第一行输入两个数n
,m
,你可以假设n<300001
并且 m<50001
;m
表示他喂了m
次。
第二行n
个整数,表示第i
只狗的漂亮值为 a i a_i ai。
接下来m
行,每行3
个整数i
,j
,k
表示这次喂食喂第i
到第j
只狗中第k
漂亮的狗的漂亮值。
输出格式
M
行,每行一个整数,表示每一次喂的那只狗漂亮值为多少。
输入
7 2
1 5 2 6 3 7 4
1 5 3
2 7 1
输出
3
2
题解
区间问题,给出若干区间,求出区间内的第k
大,且每个区间互不重叠,莫队模板题。
每次查询第k大可以利用Splay实现 O ( l o g n ) O(logn) O(logn)时间复杂度内的查询。
首先对所有需要求解的区间按照位置进行从左到右排序,然后利用双指针逐步靠近这个区间直至刚好重叠,每次指针移动就添加或删除对应的元素,m
的区间遍历完只需要双指针各访问一次,即 O ( 2 n ) O(2n) O(2n),每次查询 O ( l o g n ) O(logn) O(logn),总时间复杂度 O ( n l o g n ) O(n\ logn) O(n logn)。
代码
// #pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 300005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') {
if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') {
x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
#define ls(x) T[x].ch[0]
#define rs(x) T[x].ch[1]
#define fa(x) T[x].fa
#define root T[0].ch[1]
struct node {
int fa; //父节点
int ch[2]; //0代表左儿子,1代表右儿子
int val; //权值
int rec; //这个权值的节点出现的次数
int size; //子节点的数量(包含这个点)
} T[maxn];
int tot = 0, pointnum = 0;
void update(int x) {
T[x].size = T[ls(x)].size + T[rs(x)].size + T[x].rec; }
int ident(int x) {
return T[fa(x)].ch[0] == x ? 0 : 1; }
void connect(int x, int fa, int how) {
T[fa].ch[how] = x;
T[x].fa = fa;
}
void rotate(int x) {
int Y = fa(x), R = fa(Y);
int Yson = ident(x), Rson = ident(Y);
connect(T[x].ch[Yson ^ 1], Y, Yson);
connect(Y, x, Yson ^ 1);
connect(x, R, Rson);
update(Y);
update(x);
}
void splay(int x, int to) {
to = fa(to);
while (fa(x) != to) {
int y = fa(x);
if (T[y].fa == to)
rotate(x);
else if (ident(x) == ident(y))
rotate(y), rotate(x);
else
rotate(x), rotate(x);
}
}
int newnode(int v, int f) {
T[++tot].fa = f;
T[tot].rec = T[tot].size = 1;
T[tot].val = v;
return tot;
}
void Insert(int x) {
int now = root;
if (root == 0) {
newnode(x, 0); root = tot; }
else {
while (1) {
T[now].size++;
if (T[now].val == x) {
T[now].rec++;
splay(now, root);
return;
}
int nxt = x < T[now].val ? 0 : 1;
if (!T[now].ch[nxt]) {
int p = newnode(x, now);
T[now].ch[nxt] = p;
splay(p, root);
return;
}
now = T[now].ch[nxt];
}
}
}
int find(int x) {
int now = root;
while (1) {
if (!now) return 0;
if (T[now].val == x) {
splay(now, root);
return now;
}
int nxt = x < T[now].val ? 0 : 1;
now = T[now].ch[nxt];
}
}
void delet(int x) {
int pos = find(x);
if (!pos) return;
if (T[pos].rec > 1) {
T[pos].rec--, T[pos].size--;
return;
} else {
if (!T[pos].ch[0] && !T[pos].ch[1]) {
root = 0;
return;
} else if (!T[pos].ch[0]) {
root = T[pos].ch[1];
T[root].fa = 0;
return;
} else {
int left = T[pos].ch[0];
while (T[left].ch[1]) left = T[left].ch[1];
splay(left, T[pos].ch[0]);
connect(T[pos].ch[1], left, 1);
connect(left, 0, 1); //
update(left);
}
}
}
int rak(int x) {
return T[ls(find(x))].size + 1;
}
int arank(int x) {
int now = root;
while (1) {
int tem_num = T[now].size - T[T[now].ch[1]].size;
if (T[T[now].ch[0]].size < x && x <= tem_num) {
splay(now, root);
return T[now].val;
}
if (x < tem_num)
now = T[now].ch[0];
else
now = T[now].ch[1], x -= tem_num;
}
}
int lower(int x) {
int now = root, ans = -inf;
while (now) {
if (T[now].val <= x) ans = max(ans, T[now].val);
int nxt = x <= T[now].val ? 0 : 1; //这里需要特别注意
now = T[now].ch[nxt];
}
return ans;
}
int upper(int x) {
int now = root, ans = inf;
while (now) {
if (T[now].val >= x) ans = min(ans, T[now].val);
int nxt = x < T[now].val ? 0 : 1;
now = T[now].ch[nxt];
}
return ans;
}
struct que{
int l, r, i, k;
que(){
}
que(int l, int r, int k, int i): l(l), r(r), k(k), i(i) {
}
} a[50005];
int b[300005];
int ans[50005];
struct cmpf {
inline bool operator() (const que &a, const que &b) {
return a.l < b.l;
}
};
int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
freopen("in.txt", "r", stdin);
debug = 1;
#endif
time_t beg, end;
if(debug) beg = clock();
int n = read(), m = read();
_rep(i, 1, n) b[i] = read();
_for(i, m) a[i].l = read(), a[i].r = read(), a[i].k = read(), a[i].i = i;
sort(a, a + m, cmpf());
int l = 1, r = 0;
_for(i, m) {
while(r < a[i].r) {
++r;
Insert(b[r]);
}
while(l < a[i].l) {
delet(b[l]);
++l;
}
ans[a[i].i] = arank(a[i].k);
}
_for(i, m) printf("%d\n", ans[i]);
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
return 0;
}