ICode9

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

P3380 【模板】二逼平衡树(树套树)

2021-09-14 19:04:59  阅读:187  来源: 互联网

标签:qr 树套 int uniarr tr son unicnt P3380 模板


传送门

  • 查询 k k k 在区间内的排名
  • 查询区间内排名为 k k k的值
  • 修改某一位值上的数值
  • 查询 k k k 在区间内的前驱(前驱定义为严格小于 x x x,且最大的数,若不存在输出 − 2147483647 -2147483647 −2147483647)
  • 查询 k k k 在区间内的后继(后继定义为严格大于 x x x,且最小的数,若不存在输出 2147483647 2147483647 2147483647)

分析

对于静态区间第K大来说,那就上主席树吧
如果动态的话,就树套树了
如果是双动态的话,那就树套树套树了(大雾)
此时我们只需要实现三个功能即可

  • 根据值查询排名
  • 根据排名查值
  • 修改值

对于一棵静态区间第K大的主席树来说,维护的是一个前缀和
一旦某一个版本(位置)的值改变了,那么必须重构这个版本(位置)往后的所有版本状态
此时修改复杂度最差为 n ∗ l o g ( n ) n*log(n) n∗log(n),我不能接受
那么什么能够在短时间维护一个前缀和的修改呢?
我们想到了树状数组,每次 l o g ( n ) log(n) log(n)时间修改一个位置
查询也是 l o g ( n ) log(n) log(n)的

我们对树状数组和主席树进行组装,树状数组的每一个节点都表示着主席树的某一系列版本
对于要查询某个区间的版本情况,找到需要的左端点版本对应的一系列树状数组维护的版本 l − 1 l-1 l−1,以及右端点版本 r r r(共有将近 l o g ( n ) log(n) log(n)个版本,使用 lowbit 预处理出这一系列版本)
在这两个主席树系列版本上进行差分

修改值也是先预处理出这一系列版本,在这 l o g ( n ) log(n) log(n)个版本中更新

对于第三第四个操作
通过第一个和第二个操作的组合,就能实现

代码

//P3380 
/*
  @Author: YooQ
*/
#include <bits/stdc++.h>
using namespace std;
#define sc scanf
#define pr printf
#define ll long long
#define int long long
#define FILE_OUT freopen("out", "w", stdout);
#define FILE_IN freopen("P3380_1.in", "r", stdin);
#define debug(x) cout << #x << ": " << x << "\n";
#define AC 0
#define WA 1
#define INF 0x3f3f3f3f
const ll MAX_N = 1e6+5;
const ll MOD = 1e9+7;
int N, M, K;

int arr[MAX_N];
int uniarr[MAX_N];
int unicnt = 0;

struct Qr {
	int opt, l, r, k;
}qr[MAX_N];

struct Tr {
	int k, l, r;
}tr[MAX_N*25];

int indx = 0;
int root[MAX_N];

void update(int&rt, int l, int r, int x, int k) {
	if (!rt) rt = ++indx;
	tr[rt].k += k;
	if (l == r) {
		return;
	}
	int mid = l + ((r-l)>>1);
	if (x <= mid) update(tr[rt].l, l, mid, x, k);
	else update(tr[rt].r, mid+1, r, x, k);
}

int query(int rt, int l, int r, int x, int y) {
	if (!rt) return 0;
	if (x <= l && r <= y) {
		return tr[rt].k;
	}
	int mid = l + ((r-l)>>1);
	if (y <= mid) return query(tr[rt].l, l, mid, x, y);
	if (x  > mid) return query(tr[rt].r, mid+1, r, x, y);
	return query(tr[rt].l, l, mid, x, y) + query(tr[rt].r, mid+1, r, x, y);
}

int cnt[2];
int son[2][MAX_N];

int kth(int l, int r, int k) {
	if (l == r) {
		return l;
	}
	int mid = l + ((r-l)>>1);
	int lsum = 0, sum = 0;
	for (int i = 1; i <= cnt[1]; ++i) {
		sum += tr[son[1][i]].k;
		lsum += tr[tr[son[1][i]].l].k;
	}
	for (int i = 1; i <= cnt[0]; ++i) {
		sum -= tr[son[0][i]].k;
		lsum -= tr[tr[son[0][i]].l].k;
	}
	if (lsum >= k) {
		for (int i = 1; i <= cnt[0]; ++i) {
			son[0][i] = tr[son[0][i]].l;
		}
		for (int i = 1; i <= cnt[1]; ++i) {
			son[1][i] = tr[son[1][i]].l;
		}
		return kth(l, mid, k);
	} else {
		for (int i = 1; i <= cnt[0]; ++i) {
			son[0][i] = tr[son[0][i]].r;
		}
		for (int i = 1; i <= cnt[1]; ++i) {
			son[1][i] = tr[son[1][i]].r;
		}
		return kth(mid+1, r, k - lsum);
	}
}

int rak(int x) {
	int sum = 0;
	int t;
	for (int i = 1; i <= cnt[1]; ++i) {
		t = query(son[1][i], 1, unicnt, 1, x);
		sum += t;
	}
	for (int i = 1; i <= cnt[0]; ++i) {
		t = query(son[0][i], 1, unicnt, 1, x);
		sum -= t;
	}
	return sum;
}

inline int lowbit(int x) {
	return x&-x;
}

void modify(int x, int k, int w) {
	while (x <= N) {
		update(root[x], 1, unicnt, k, w);
		x += lowbit(x);
	}
}

void init(int l, int r) {
	memset(cnt, 0, sizeof cnt);
	--l;
	while (l) {
		son[0][++cnt[0]] = root[l];
		l -= lowbit(l);
	}
	while (r) {
		son[1][++cnt[1]] = root[r];
		r -= lowbit(r);
	}
}

/**
9 1
4 2 2 1 9 4 0 1 1
2 1 4 3
**/
void solve(){
	sc("%lld%lld", &N, &M);
	uniarr[++unicnt] = -2147483647;
	uniarr[++unicnt] = 2147483647;
	for (int i = 1; i <= N; ++i) {
		sc("%lld", &arr[i]);
		uniarr[++unicnt] = arr[i];
	}
	
	int opt, l, r, k;
	for (int i = 1; i <= M; ++i) {
		sc("%lld%lld%lld", &qr[i].opt, &qr[i].l, &qr[i].r);
		if (qr[i].opt == 1) {
			sc("%lld", &qr[i].k);
			uniarr[++unicnt] = qr[i].k;
		} else if (qr[i].opt == 2) {
			sc("%lld", &qr[i].k);
		} else if (qr[i].opt == 3) {
			qr[i].k = qr[i].r;
			uniarr[++unicnt] = qr[i].k;
		} else if (qr[i].opt == 4) {
			sc("%lld", &qr[i].k);
			uniarr[++unicnt] = qr[i].k;
		} else {
			sc("%lld", &qr[i].k);
			uniarr[++unicnt] = qr[i].k;
		}
	}
	
	sort(uniarr+1, uniarr+1+unicnt);
	unicnt = unique(uniarr+1, uniarr+1+unicnt) - uniarr - 1;
	
	
	for (int i = 1; i <= N; ++i) {
		arr[i] = lower_bound(uniarr+1, uniarr+1+unicnt, arr[i]) - uniarr;
		modify(i, arr[i], 1);
	}
	for (int i = 1; i <= M; ++i) {
		if (qr[i].opt != 2) qr[i].k = lower_bound(uniarr+1, uniarr+1+unicnt, qr[i].k) - uniarr;
		if (qr[i].opt == 1) {
			init(qr[i].l, qr[i].r);
			pr("%lld\n", rak(qr[i].k-1) + 1);
		} else if (qr[i].opt == 2) {
			init(qr[i].l, qr[i].r);
			pr("%lld\n", uniarr[kth(1, unicnt, qr[i].k)]);
		} else if (qr[i].opt == 3) {
			modify(qr[i].l, arr[qr[i].l], -1);
			modify(qr[i].l, arr[qr[i].l] = qr[i].k, 1);
		} else if (qr[i].opt == 4) {
			init(qr[i].l, qr[i].r);
			int rk = rak(qr[i].k-1);
			init(qr[i].l, qr[i].r);
			pr("%lld\n", uniarr[kth(1, unicnt, rk)]);
		} else {
			init(qr[i].l, qr[i].r);
			int rk = rak(qr[i].k);
			init(qr[i].l, qr[i].r);
			pr("%lld\n", uniarr[kth(1, unicnt, rk+1)]);
		}
	}
	
}

signed main()
{
	#ifndef ONLINE_JUDGE
	FILE_IN
	FILE_OUT
	#endif
	int T = 1;//cin >> T;
	while (T--) solve();

	return AC;
}

标签:qr,树套,int,uniarr,tr,son,unicnt,P3380,模板
来源: https://blog.csdn.net/qq_45754027/article/details/120293108

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

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

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

ICode9版权所有