ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解 P2617 Dynamic Rankings

2021-03-07 14:33:47  阅读:201  来源: 互联网

标签:int 题解 线段 Dynamic Rankings leq 权值 include


题目描述

Link

给定一个含有 \(n\) 个数的序列 \(a_1,a_2 \dots a_n\) ,需要进行 \(m\) 次操作,每次操作是下面的两种之一:

  • Q l r k 表示查询下标在区间 \([l,r]\) 中的第 \(k\) 小的数
  • C x y 表示将 \(a_x\) 改为 \(y\) 。

\(1 \leq n ,m \leq 10^5 ,1 \leq a_i,y \leq 10^9\) 。

Solution

P3332 [ZJOI2013]K大数查询 基本上一样,大部分内容在前面的题解 题解 P3332 [ZJOI2013]K大数查询 已经写过了。

由于只有单点修改,所以本题直接用权值线段树套动态开点单点修改线段树就可以。

对于本题的 C 操作,我们可以看成在 \(x\) 这个位置删掉了一个 \(a_x\) ,又加上了一个 \(y\) 之后的结果。

所以我们可以分成两次操作:

  • 在权值线段树内找到权值为 \(a_x\) 的点,然后把一路上的所有点所对应的内层线段树的 \(x\) 这个位置上 \(-1\) 。
  • 在权值线段树内找到权值为 \(y\) 的点,然后把一路上的所有点所对应的内层线段树的 \(x\) 这个位置上 \(+1\) 。

同样的,本题需要离散化,所以要先读入所有的操作再进行操作。

两个坑点:

  • 和上题不同的是,这题是找 \(k\) 小,而不是 \(k\) 大,所以我们在查询的时候要先看左儿子落在 \([l,r]\) 的数量,如果不足 \(k\) 个就进入右儿子。
  • 离散化的时候原数组记得也要离散化。

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
using namespace std;
inline int read() {
	int num = 0 ,f = 1; char c = getchar();
	while (!isdigit(c)) f = c == '-' ? -1 : f ,c = getchar();
	while (isdigit(c)) num = (num << 1) + (num << 3) + (c ^ 48) ,c = getchar();
	return num * f;
}
inline int max(int a ,int b) {return a > b ? a : b;}
inline int min(int a ,int b) {return a < b ? a : b;}
const int N = 1e5 + 5 ,M = N << 1 ,S = N * 17 * 17;
struct Segment1 {
	struct node {
		int l ,r ,sum;
		node (int l = 0 ,int r = 0 ,int sum = 0) : l(l) ,r(r) ,sum(sum) {}
	}t[S]; int tot;
	Segment1 () : tot(0) {}
	inline void update(int now) {
		t[now].sum = t[t[now].l].sum + t[t[now].r].sum;
	}
	inline void modify(int &now ,int l ,int r ,int q ,int k) {
		if (!now) now = ++tot;
		if (l == r) {t[now].sum += k; return ;}
		int mid = (l + r) >> 1;
		if (q <= mid) modify(t[now].l ,l ,mid ,q ,k);
		else modify(t[now].r ,mid + 1 ,r ,q ,k);
		update(now);
	}
	inline int query(int &now ,int l ,int r ,int ql ,int qr) {
		if (!now) return 0;
		if (ql <= l && r <= qr) return t[now].sum;
		int mid = (l + r) >> 1 ,ans = 0;
		if (ql <= mid) ans += query(t[now].l ,l ,mid ,ql ,qr);
		if (qr > mid) ans += query(t[now].r ,mid + 1 ,r ,ql ,qr);
		return ans;
	}
}u;
int n;
struct Segment {
	int t[M << 2];
	Segment () {memset(t ,0 ,sizeof(t));}
	inline void modify(int now ,int l ,int r ,int p ,int q ,int k) {
		u.modify(t[now] ,1 ,n ,p ,k);
		if (l == r) return ;
		int mid = (l + r) >> 1;
		if (q <= mid) modify(now << 1 ,l ,mid ,p ,q ,k);
		else modify(now << 1 | 1 ,mid + 1 ,r ,p ,q ,k);
	}
	inline int query(int now ,int l ,int r ,int ql ,int qr ,int k) {
		if (l == r) return l;
		int mid = (l + r) >> 1 ,res = u.query(t[now << 1] ,1 ,n ,ql ,qr);
		if (res >= k) return query(now << 1 ,l ,mid ,ql ,qr ,k); //先判断左儿子
		return query(now << 1 | 1 ,mid + 1 ,r ,ql ,qr ,k - res);
	}
}t;
int m ,nums[M] ,tot;
inline int find(int val) {
	return lower_bound(nums + 1 ,nums + tot + 1 ,val) - nums;
}
struct Query {
	int opt ,x ,y ,k;
	Query (int opt = 0 ,int x = 0 ,int y = 0 ,int k = 0) :
		opt(opt) ,x(x) ,y(y) ,k(k) {}
}q[N];
char opt[3];
int a[N];
signed main() {
	n = read(); m = read();
	for (int i = 1; i <= n; i++)
		a[i] = read() ,nums[++tot] = a[i];
	for (int i = 1; i <= m; i++) {
		scanf("%s" ,opt); int x = read() ,y = read();
		if (opt[0] == 'Q') {
			int k = read();
			q[i] = Query(2 ,x ,y ,k);
		}
		else {
			nums[++tot] = y;
			q[i] = Query(1 ,x ,y);
		}
	}
	sort(nums + 1 ,nums + tot + 1);
	tot = unique(nums + 1 ,nums + tot + 1) - nums - 1;
	for (int i = 1; i <= n; i++) { //记得把 a[i] 离散化
		a[i] = find(a[i]);
		t.modify(1 ,1 ,tot ,i ,a[i] ,1);
	}
	for (int i = 1; i <= m; i++) {
		if (q[i].opt == 2)
			printf("%d\n" ,nums[t.query(1 ,1 ,tot ,q[i].x ,q[i].y ,q[i].k)]);
		else {
			int c = find(q[i].y);
			t.modify(1 ,1 ,tot ,q[i].x ,a[q[i].x] ,-1);
			t.modify(1 ,1 ,tot ,q[i].x ,c ,1);
			a[q[i].x] = c;
		}
	}
	return 0;
}

标签:int,题解,线段,Dynamic,Rankings,leq,权值,include
来源: https://www.cnblogs.com/Dragon-Skies/p/14494531.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有