牛客多校第七场E Find the median

牛客多校第七场E Find the median

题意:每次在一个空区间内加入[L,R]区间内所有的数,然后问每次加入后的中位数是什么。

题解:一道线段树的题目。
A:线段树的叶子节点维护了一个区间,这个区间是[L,R+1),为什么是这区间?(因为这样能不重不漏的包含所有的区间,每次查询的时候也不会漏掉,自己画一颗线段树基本能明白了)。
B:然后查询的时候,记录一下这个区间的个数,然后减去这个区间内有能最大的容纳的不同的个数,最后相减得到答案。

闲话:太久没写线段树,导致这题A得太慢了。以后上来就找线段树的题目吧。

代码:

#include<cstdio>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
const int mx = 5e5 + 7;
typedef long long ll;
struct node {
	ll v;
	ll index;
	ll c;
	ll lazy;
}tree[mx<<3];
int n;
ll x[mx], y[mx], l[mx], r[mx];
ll qc[mx << 3];
ll a, b, c, mo;
void pushup(int id) {
	tree[id].c = tree[id << 1].c + tree[id << 1 | 1].c;
}
void pushdown(int id) {
	if (tree[id].lazy) {
		tree[id << 1].lazy += tree[id].lazy;
		tree[id << 1 | 1].lazy += tree[id].lazy;
		tree[id << 1].c += (1LL * tree[id<<1].v * tree[id].lazy);
		tree[id << 1|1].c += (1LL * tree[id<<1|1].v * tree[id].lazy);
		tree[id].lazy = 0;
	}
}
void build(int id, int l, int r) {
	if (l == r) {
		tree[l].index = id;
		tree[id].v = qc[l] - qc[l - 1]; 
		return;
	}
	int mid = (l + r) >> 1;
	build(id<<1, l, mid);
	build(id<<1|1, mid + 1, r);
	tree[id].v = tree[id << 1].v + tree[id << 1 | 1].v;
}
void update(int id, int l, int r,int rl,int rr,int lz) {
	if (rl < l && rr >= r) { //??????
		tree[id].lazy += lz;
		tree[id].c += (1LL * lz * tree[id].v);
		return;
	}
	if (rl >= r || rr < l) return;
	pushdown(id);
	int mid = (l + r) >> 1;
	update(id << 1, l, mid, rl, rr, lz);
	update(id << 1 | 1, mid + 1, r, rl, rr, lz);
	pushup(id);
}
ll query(int id, int l, int r,int rl,int rr) {
	if (rl <= l && rr >= r) return tree[id].c;
	if (rl > r || rr < l) return 0;
	pushdown(id);
	int m = (l + r) / 2;
	ll ans = 0;
	ans += query(id << 1, l, m, rl, rr) + query(id << 1 | 1, m + 1, r, rl, rr);
	return ans;
}
int main() {
	scanf("%d", &n);
	scanf("%lld%lld%lld%lld%lld%lld", &x[1], &x[2], &a, &b, &c, &mo);
	for (int i = 3; i <= n; i++)
		x[i] = (a * x[i - 1] + b * x[i - 2] + c) % mo;
	scanf("%lld%lld%lld%lld%lld%lld", &y[1], &y[2], &a, &b, &c, &mo);
	for (int i = 3; i <= n; i++)
		y[i] = (a * y[i - 1] + b * y[i - 2] + c) % mo;
	ll cnt = 0;
	for (int i = 1; i <= n; i++) {
		l[i] = min(x[i], y[i]) + 1;
		r[i] = max(x[i], y[i]) + 1;
		qc[++cnt] = l[i];
		qc[++cnt] = r[i] + 1;
	}
	sort(1 + qc, 1 + qc +cnt);
	cnt = unique(qc + 1, qc + 1 +cnt) - qc - 1;
	ll num = 0;
	build(1, 1, cnt);
	for (int i = 1; i <= n; i++) {
		num += r[i] - l[i] + 1;
		int f1 = lower_bound(qc + 1, qc + 1 + cnt, l[i]) - qc;
		int f2 = lower_bound(qc + 1, qc + 1 + cnt, r[i] + 1) - qc;
		update(1, 1, cnt, f1, f2, 1);
		int L = 1, R = cnt, mid;
		ll ans = 0, m = (num + 1) / 2;
		while (L < R) {
			mid = (L + R) >> 1;
			ans = query(1, 1, cnt, 1, mid);
			if (ans >= m) R = mid;
			else L = mid + 1;
		}
		ans = query(1, 1, cnt, 1, L);
		ll trans = ans - m;
		ll re = tree[tree[L].index].c / tree[tree[L].index].v;
		ll ret = qc[L] - trans / re - 1;
		printf("%lld\n", ret);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值