2019牛客暑期多校训练营(第七场)E Governing sand【树状数组+离散化】【二分】

题意:

给你

x1, x2, y1, y2, a1, a2,  b1,  b2,  c1,  c2,  m1,  m2;

推导出接下来的每一项x和y  

Xi = (a1 * Xi-1   + b1 * Xi-2 + c1) % m1

Yi = (a2 * Yi-1   + b2 * Yi-2 + c2) % m2

Ri = max(Xi, Yi)

Li = min(Xi, Yi)

n次操作   往序列里面(初始为空)加入  Li ~ Ri   (Ri - Li + 1) 个数  求当前中位数为多少  偶数个取中间偏前的数字

题目链接:

https://ac.nowcoder.com/acm/contest/887/E

题解:

先对所有的L, R 离散化

建两个树状数组

然后二分枚举中位数

树状数组求和前面有多少个数字

第一个bit1 树状数组的求一定不对 因为如果前面有多个L  比 R 多

那么我们就要把R在后面给他加回来

所以bit2记录的是前面有多少个L

AC_code:

#include
using namespace std;
#define maxn 400010
#define ll long long
int n, x[maxn], y[maxn], l[maxn], r[maxn];
ll a1,a2, b1, b2, c1, c2, m1, m2;
int z[maxn<<1], cnt;
ll bit1[maxn], bit2[maxn];
int lowbit(int x) {
	return x&(-x);
}
void add(ll bit[], int p, int x) {
	for(int i = p; i <= cnt; i += lowbit(i)) {
		bit[i] += x;
	}
}
ll query(ll bit[], int p) {
	ll ans = 0;
	for(int i = p; i > 0; i -= lowbit(i)) {
		ans += bit[i];
	}
	return ans;
}
int main() {
	cin>>n;
	cin>> x[1] >> x[2] >> a1 >> b1 >> c1 >> m1;
	cin>> y[1] >> y[2] >> a2 >> b2 >> c2 >> m2;
	for(int i = 1; i <= n; i++) {
		if(i > 2) {
			x[i] = (a1 * x[i-1] + b1 * x[i-2] + c1) % m1;
			y[i] = (a2 * y[i-1] + b2 * y[i-2] + c2) % m2;
		}
		l[i] = min(x[i], y[i]) + 1;
		r[i] = max(x[i], y[i]) + 1;
		z[++cnt] = l[i];
		z[++cnt] = r[i] + 1;
	}
	sort(z+1, z+cnt+1);
	cnt = unique(z+1, z+cnt+1) - z - 1;
	ll t = 0;
	for(int i = 1; i <= n; i++){
		t += r[i] - l[i] + 1;
		int L = lower_bound(z+1, z+cnt+1, l[i]) - z;
		int R = lower_bound(z+1, z+cnt+1, r[i]+1) - z;
		add(bit1, L, -l[i]);
		add(bit1, R, r[i]+1);
		add(bit2, L, 1);
		add(bit2, R, -1);
		L = 1, R = 1e9;
		while(L < R){
			int mid = (L + R) / 2;
			int pos = upper_bound(z+1, z+cnt+1, mid) -z - 1;
			ll tmp = query(bit1, pos) + query(bit2, pos) * (mid + 1);
			if(tmp < (t+1)/2){
				L = mid + 1;
			}else {
				R = mid;
			}
		}
		printf("%d\n", L);
	}

	return 0;
}

 

你可能感兴趣的:(ACM题目和算法,OJ----牛客,二分算法,数据结构----树状数组)