2019牛客暑期多校训练营(第七场) E Find the median(线段树)

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

题目描述

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]

             先将所有的点存起来离散化之后建立线段树,每个点保存的是这个点到下一个点之间的所有点出现的次数。之后按权值线段树查找就可以了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 400010;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll inf = 1LL * 800050 * 1e9;
ll c[maxn * 8]; ll sot[maxn * 3], cnt = 1;
ll step[maxn][2]; ll lazy[maxn * 8];
int id(ll x) {
	return lower_bound(sot, sot + cnt, x) - sot;
}
void build(int l, int r, int rt) {
	c[rt] = lazy[rt] = 0;
	if (l == r)return;
	int m = (l + r) >> 1;
	build(lson); build(rson);
}
void pushdown(int l, int r, int rt) {
	if (lazy[rt] != 0) {
		int mid = (l + r) >> 1;
		lazy[rt << 1] += lazy[rt]; lazy[rt << 1 | 1] += lazy[rt];
		c[rt << 1 | 1] += lazy[rt] * (sot[r + 1] - sot[mid + 1]);
		c[rt << 1] += lazy[rt] * (sot[mid + 1] - sot[l]);
		lazy[rt] = 0;
	}
}
void pushup(int rt) {
	c[rt] = c[rt << 1] + c[rt << 1 | 1];
}
void add(int l, int r, int rt, int L, int R) {
	if (L <= l && r <= R) {
		c[rt] += (sot[r + 1] - 1 - sot[l] + 1);
		lazy[rt] += 1;
		return;
	}
	int m = (l + r) >> 1;
	pushdown(l, r, rt);
	if (L <= m) add(lson, L, R);
	if (m < R) add(rson, L, R);
	pushup(rt);
}
ll query(int l, int r, int rt, ll k) {
	if (l == r) {
		ll t = (k - 1) / lazy[rt];
		return sot[l] + t;
	}
	int m = (l + r) >> 1;
	pushdown(l, r, rt);
	if (c[rt << 1] >= k) return query(lson, k);
	else return  query(rson, k - c[rt << 1]);
}
int main() {
	int te; ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	int n; cin >> n;
	ll x1, x2, a1, b1, c1, m1;
	ll y1, y2, a2, b2, c2, m2;
	cin >> x1 >> x2 >> a1 >> b1 >> c1 >> m1;
	cin >> y1 >> y2 >> a2 >> b2 >> c2 >> m2;
	step[0][0] = min(x1, y1) + 1; step[0][1] = max(x1, y1) + 1;
	step[1][0] = min(x2, y2) + 1; step[1][1] = max(x2, y2) + 1;
	sot[cnt++] = step[0][0];    sot[cnt++] = ++step[0][1];  sot[cnt++] = step[1][0];    sot[cnt++] = ++step[1][1];
	ll sum = 0;
	for (int i = 2; i < n; i++) {
		ll a = (a1*x2) % m1 + (b1*x1) % m1 + c1; a %= m1;
		ll b = (a2*y2) % m2 + (b2*y1) % m2 + c2; b %= m2;
		step[i][0] = min(a, b) + 1;
		step[i][1] = max(a, b) + 1 + 1;
		sot[cnt++] = step[i][0];
		sot[cnt++] = step[i][1];
		x1 = x2; x2 = a;
		y1 = y2; y2 = b;
	}
	sot[cnt] = sot[cnt - 1] + 1; sort(sot + 1, sot + cnt);
	cnt = unique(sot + 1, sot + 1 + cnt) - sot - 1;
	memset(c, 0, sizeof c); build(1, cnt, 1);
	for (int i = 0; i < n; i++) {
		sum += step[i][1] - step[i][0];
		add(1, cnt, 1, id(step[i][0]), id(step[i][1]) - 1);
		cout << query(1, cnt, 1, (sum + 1) / 2) << "\n";
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值