洛谷P1533 可怜的狗狗(莫队+Splay)

时间限制:1.00s
内存限制:125.00MB
OJ:洛谷P1533

题目背景

小卡由于公务需要出差,将新家中的狗狗们托付给朋友嘉嘉,但是嘉嘉是一个很懒的人,他才没那么多时间帮小卡喂狗狗。

题目描述

小卡家有N只狗,由于品种、年龄不同,每一只狗都有一个不同的漂亮值。漂亮值与漂亮的程度成反比(漂亮值越低越漂亮),吃饭时,狗狗们会按顺序站成一排等着主人给食物。

可是嘉嘉真的很懒,他才不肯喂这么多狗呢,这多浪费时间啊,于是他每次就只给第i只到第j只狗中第k漂亮的狗狗喂食(好狠心的人啊)。而且为了保证某一只狗狗不会被喂太多次,他喂的每个区间(i,j)不互相包含。

输入格式

第一行输入两个数nm,你可以假设n<300001 并且 m<50001m表示他喂了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;
}

猜你喜欢

转载自blog.csdn.net/weixin_42856843/article/details/109330695