牛客第七场 E Find the median —— 离散区间 + 线段树

题目链接:点我啊╭(╯^╰)╮

题目大意:

    每次加入一个区间的数,求中位数

解题思路:

    区间离散化
    线段树每个节点表示离散之后的区间的数目总和
    注意离散区间的时候右端点要加一
    最后线段树二分完之后要处理一下

核心:线段树处理离散区间

#include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
using namespace std;
typedef long long ll;
typedef pair <int,int> pii;
const ll mod = 998244353;
const int maxn = 2e6 + 10;
int n, a1, b1, c1, m1;
int a2, b2, c2, m2;
int ls[maxn], ans[maxn];
int l[maxn], r[maxn], x[maxn], y[maxn];
ll t[maxn<<2], lazy[maxn<<2], len[maxn], id[maxn];

void pushup(int rt){
	t[rt] = t[rt<<1] + t[rt<<1|1];
}
void pushdown(int rt){
	if(lazy[rt]){
		t[rt<<1] += lazy[rt] * len[rt<<1];
		t[rt<<1|1] += lazy[rt] * len[rt<<1|1];
		lazy[rt<<1] += lazy[rt];
		lazy[rt<<1|1] += lazy[rt];
		lazy[rt] = 0;
	}
}
void build(int l, int r, int rt){
	t[rt] = lazy[rt] = 0;
	if(l==r) {
		len[rt] = id[l];
		return;
	}
	int m = l + r >> 1;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
	len[rt] = len[rt<<1] + len[rt<<1|1];
}
void update(int L,int R,int l,int r,int rt){
	if(l>R || r<L) return;
	if(L<=l && r<=R){
		t[rt] += len[rt];
		lazy[rt]++;
		return ;
	}
	pushdown(rt);
	int m = l + r >> 1;
	update(L,R,l,m,rt<<1);
	update(L,R,m+1,r,rt<<1|1);
	pushup(rt);
}
int query(ll tot, int l, int r, int rt){
	if(l==r){
		ll num = t[rt] / len[rt];
		return ls[l] + (tot - 1) / num;
	}
	pushdown(rt);
	int m = l + r >> 1;
	if(t[rt<<1]>=tot) return query(tot,l,m,rt<<1);
	else return query(tot-t[rt<<1],m+1,r,rt<<1|1);
}

int main() {
	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);
	l[1] = min(x[1], y[1]) + 1, r[1] = max(x[1], y[1]) + 1;
	l[2] = min(x[2], y[2]) + 1, r[2] = max(x[2], y[2]) + 1;
	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;
		l[i] = min(x[i], y[i]) + 1, r[i] = max(x[i], y[i]) + 1;
	}
	
	for(int i=1; i<=n; i++) ls[i] = l[i], ls[i+n] = r[i] + 1;
	sort(ls+1, ls+1+n+n);
	int cnt = unique(ls+1, ls+1+n+n) - ls - 1;
	for(int i=1; i<=cnt; i++) id[i] = ls[i+1] - ls[i];
	id[cnt] = 1;
	
	build(1,cnt,1);
	for(int i=1; i<=n; i++){
		int u = lower_bound(ls+1, ls+cnt+1, l[i]) - ls;
		int v = lower_bound(ls+1, ls+cnt+1, r[i]+1) - ls;
		update(u,v-1,1,cnt,1);
		ll sum = (t[1] + 1) / 2;
		ans[i] = query(sum,1,cnt,1);
	}
	for(int i=1; i<=n; i++) printf("%d\n", ans[i]);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值