2019牛客多校 第七场 E Find the median 线段树 用点维护区间

链接:https://ac.nowcoder.com/acm/contest/887/E
来源:牛客网
 

Find the median

时间限制:C/C++ 3秒,其他语言6秒
空间限制:C/C++ 131072K,其他语言262144K
64bit IO Format: %lld

题目描述

Let median of some array be the number which would stand in the middle of this array if it was sorted beforehand. If the array has even length let median be smallest of of two middle elements. For example, median of the array [10,3,2,3,2] is 3 (i.e. [2,2,3‾,3,10][2,2,\underline{3},3,10][2,2,3​,3,10]). Median of the array [1,5,8,1] is 1 (i.e. [1,1‾,5,8][1,\underline{1},5,8][1,1​,5,8]).

At first, you're given an empty sequence. There are N operations. The i-th operation contains two integers LiL_iLi​ and RiR_iRi​. This means that adding Ri−Li+1R_i-L_i+1Ri​−Li​+1 integers Li,Li+1,...,RiL_i, L_i+1, ... , R_iLi​,Li​+1,...,Ri​ into the sequence. After each operation, you need to find the median of the sequence.

输入描述:

The first line of the input contains an integer N (1≤N≤400000)N\ (1 \leq N \leq 400000)N (1≤N≤400000) as described above.

The next two lines each contains six integers in the following format, respectively:

- X1 X2 A1 B1 C1 M1X_1\ X_2\ A_1\ B_1\ C_1\ M_1X1​ X2​ A1​ B1​ C1​ M1​
- Y1 Y2 A2 B2 C2 M2Y_1\ Y_2\ A_2\ B_2\ C_2\ M_2Y1​ Y2​ A2​ B2​ C2​ M2​

These values are used to generate Li,RiL_i, R_iLi​,Ri​ as follows:

We define:
- Xi=(A1×Xi−1+B1×Xi−2+C1) module M1X_i = (A_1 \times X_{i-1} + B_1 \times X_{i-2} + C_1)\ module\ M_1Xi​=(A1​×Xi−1​+B1​×Xi−2​+C1​) module M1​, for i=3 to Ni = 3\ to\ Ni=3 to N
- Yi=(A2×Yi−1+B2×Yi−2+C2) module M2Y_i = (A_2 \times Y_{i-1} + B_2 \times Y_{i-2} + C_2)\ module\ M_2Yi​=(A2​×Yi−1​+B2​×Yi−2​+C2​) module M2​, for i=3 to Ni = 3\ to\ Ni=3 to N


We also define:
- Li=min(Xi,Yi)+1L_i = min(X_i, Y_i) + 1Li​=min(Xi​,Yi​)+1, for i=1 to Ni = 1\ to\ Ni=1 to N.
- Ri=max(Xi,Yi)+1R_i = max(X_i, Y_i) + 1Ri​=max(Xi​,Yi​)+1, for i=1 to Ni = 1\ to\ Ni=1 to N.

Limits:
1≤N≤4000001 \leq N \leq 4000001≤N≤400000
0≤A1<M10 \leq A_1 < M_10≤A1​<M1​
0≤A2<M20 \leq A_2 < M_20≤A2​<M2​
0≤B1<M10 \leq B_1 < M_10≤B1​<M1​
0≤B2<M20 \leq B_2 < M_20≤B2​<M2​
0≤C1<M10 \leq C_1 < M_10≤C1​<M1​
0≤C2<M20 \leq C_2 < M_20≤C2​<M2​
0≤X1<M10 \leq X_1 < M_10≤X1​<M1​
0≤X2<M10 \leq X_2 < M_10≤X2​<M1​
0≤Y1<M20 \leq Y_1 < M_20≤Y1​<M2​
0≤Y2<M20 \leq Y_2 < M_20≤Y2​<M2​
1≤M1≤1091 \leq M_1 \leq 10^91≤M1​≤109
1≤M2≤1091 \leq M_2 \leq 10^91≤M2​≤109

输出描述:

You should output lines. Each line contains an integer means the median.

示例1

输入

复制

5
3 1 4 1 5 9
2 7 1 8 2 9

输出

复制

3
4
5
4
5

说明

L = [3, 2 ,4, 1, 7]

R = [4, 8, 8, 3, 9]

题意:给你n个区间,每次往你现有的数中加上l,l+1,.....,r-1,r这些数,求现在所有数的中位数是啥

题解:因为这个是给出的区间,所以我们需要把区间离散化成点,用一个点来表示一个区间,比如 区间 [1, 7]  [ 3, 10] 我们就可以划分为[1,2] [3,7] [8,10]  划分的时候可以定个标准,先把左右区间排序,两个连续的点,作为区间的l,r,如果这个点是之前L,那就直接作为该区间的L,如果之前是区间的R,那就用R+1作为改区间的L,对于改区间的R恰好相反,这样我们用结构体就可以实现了,但是现在有一个更好的操作方法,就是,让原先的R加一,然后比如排序后连续两个数 b[x] b[x+1],那么就得到区间[b[x], b[x + 1] - 1],这样就能把前面讨论的所有情况就都包括了,然后线段树维护下每个区间的长度以及数的数量,然后需要laz标记一下,剩下的就是基本操作了,要注意的一点是,因为R我们是记录的R+1,所有在找pos的时候也是通过R+1来找,但是别忘了要减一下1,因为R+1是在后面那个区间,所以要减一。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 400100;
struct node {
	int l, r;
	ll sum, len, laz;
}tree[N * 2 * 4];
int n, X[N], Y[N];
int b[N * 2], len;
int A1, B1, C1, M1, A2, B2, C2, M2;
void build(int l, int r, int cur) {
	tree[cur].l = l;
	tree[cur].r = r;
	tree[cur].sum = tree[cur].laz = 0;
	if(l == r) {
		tree[cur].len = b[l + 1] - b[l];
		return;
	}
	int mid = (r + l ) >> 1;
	build(l, mid, cur << 1);
	build(mid + 1, r, cur << 1 | 1);
	tree[cur].len = tree[cur << 1].len + tree[cur << 1 | 1].len;
}
void pushdown(int cur) {
	if(tree[cur].laz) {
		tree[cur << 1].laz += tree[cur].laz;
		tree[cur << 1].sum += tree[cur].laz * tree[cur << 1].len;;
		tree[cur << 1 | 1].laz += tree[cur].laz;
		tree[cur << 1 | 1].sum += tree[cur].laz * tree[cur << 1 | 1].len;
		tree[cur].laz = 0;
	}
}
void update(int pl, int pr, int cur) {
	if(pl <= tree[cur].l && tree[cur].r <= pr) {
		tree[cur].sum += tree[cur].len;
		tree[cur].laz++;
		return;
	}
	pushdown(cur);
	if(pl <= tree[cur << 1].r) update(pl, pr, cur << 1);
	if(pr >= tree[cur << 1 | 1].l) update(pl, pr, cur << 1 | 1);
	tree[cur].sum = tree[cur << 1].sum + tree[cur << 1 | 1].sum;
}
int query(int cur, ll val) {
	if(tree[cur].l == tree[cur].r) {
		ll cnt = tree[cur].sum / tree[cur].len;
//		cout << cnt << " " << tree[cur].sum << endl;
		return val % cnt ? b[tree[cur].l] + val / cnt : b[tree[cur].l] + val / cnt - 1;
	}
	pushdown(cur); 
	if(tree[cur << 1].sum >= val) return query(cur << 1, val);
	else return query(cur << 1 | 1, val - tree[cur << 1].sum);
}
int main() {
	int l, r;
	ll sum = 0;
	scanf("%d", &n);
	scanf("%d %d %d %d %d %d", &X[1], &X[2], &A1, &B1, &C1, &M1);
	scanf("%d %d %d %d %d %d", &Y[1], &Y[2], &A2, &B2, &C2, &M2);
	for(int i = 3; i <= n; i++) {
		X[i] = (1LL * A1 * X[i - 1] + 1LL * B1 * X[i - 2] + C1) % M1;
		Y[i] = (1LL * A2 * Y[i - 1] + 1LL * B2 * Y[i - 2] + C2) % M2;
	}
	for(int i = 1; i <= n; i++) {
		l = min(X[i], Y[i]) + 1;
		r = max(X[i], Y[i]) + 1;
		X[i] = l;
		Y[i] = r;
		b[++len] = l;
		b[++len] = r + 1;
	}
	sort(b + 1, b + 1 + len);
	len = unique(b + 1, b + 1 + len) - (b + 1);
	for(int i = 1; i <= n; i++) {
		X[i] = lower_bound(b + 1, b + 1 + len, X[i]) - b;
		Y[i] = lower_bound(b + 1, b + 1 + len, Y[i] + 1) - b;
	}
	build(1, len - 1, 1);
	for(int i = 1; i <= n; i++) {
		update(X[i], Y[i] - 1, 1); // 注意减一 
		sum += b[Y[i]] - b[X[i]];
	//	cout << sum << endl;
		printf("%d\n", query(1, (sum + 1) / 2));
	}
	return 0;
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值