2019牛客暑期多校训练营(第七场) E Find the median 权值线段树+区间离散化

 

讲的挺好

每个叶子结点表示 大于等于当前这个点小于后面一个点的 区间,对这些点建线段树,查询区间第 (n+1)/2 大

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 4e5 + 10;
struct No{
	int rt,lazy,cnt;
	ll sum;
}no[N<<3];
int x[N], y[N], A[3], B[3], C[3], M[3], L[N], R[N];
int pre[N<<1],n,tot;
ll num[N<<3];
void spread(int rt,int l,int r){
	int tp,mid; 
	if(no[rt].lazy){
		tp =  no[rt].lazy;	mid = ( l + r ) >> 1;
		no[rt].lazy = 0;
		no[rt<<1].cnt+=tp;	no[rt<<1|1].cnt+=tp;
		no[rt<<1].lazy+=tp;	no[rt<<1|1].lazy+=tp;
		no[rt<<1].sum+= 1ll*(pre[mid] - pre[l-1])*tp;
		no[rt<<1|1].sum+=1ll*(pre[r] - pre[mid])*tp; 
	} 
}
void update(int rt,int l,int r,int L,int R){
	if(L<=l&&R>=r){
		no[rt].lazy++;	no[rt].cnt++;
		no[rt].sum+=( pre[r] - pre[l-1]);
		return ;
	}
	spread(rt,l,r);
	int mid = (l+r)>>1;
	if(L<=mid)update(rt<<1,l,mid,L,R);
	if(R>mid)update(rt<<1|1,mid+1,r,L,R);
	no[rt].sum = no[rt<<1].sum + no[rt<<1|1].sum;
} 
int query(int rt,int l,int r,ll k){
	if(l==r){
		return num[l] + (k-1)/no[rt].cnt; 	
	}
	spread(rt,l,r);
	int mid = ( l + r )>>1;
	if(no[rt<<1].sum<k) return query(rt<<1|1,mid+1,r,k-no[rt<<1].sum);
	return query(rt<<1,l,mid,k);
}
int main()
{
	cin >> n;
    cin >> x[1] >> x[2] >> A[1] >> B[1] >> C[1] >> M[1];
    cin >> y[1] >> y[2] >> A[2] >> B[2] >> C[2] >> M[2];
    for(int i = 1; i <= n; ++i) {
        if(i >= 3) {
            x[i] = (1LL * A[1] * x[i - 1] + 1LL * B[1] * x[i - 2] + C[1]) % M[1];
            y[i] = (1LL * A[2] * y[i - 1] + 1LL * B[2] * y[i - 2] + C[2]) % M[2];
        }
        L[i] = min(x[i],y[i])+1;
        R[i] = max(x[i],y[i])+2;
        num[i*2-1] = L[i];
        num[i*2] = R[i];
	}
	sort(num+1,num+2*n+1);
	tot = unique(num+1,num+2*n+1) - num - 1;
	num[tot+1] = num[tot];
	
	for(int i=1;i<=tot;++i){
		pre[i] = pre[i-1] + num[i+1] - num[i];  	
	}
	ll now = 0;
	for(int i=1;i<=n;++i){
		L[i] = lower_bound(num+1,num+tot+1,L[i]) - num; 
		R[i] = lower_bound(num+1,num+tot+1,R[i]) - num - 1;
		now+=pre[R[i]] - pre[L[i]-1];
		update(1,1,tot,L[i],R[i]);
		printf("%d\n",query(1,1,tot,(now+1)/2));
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wym_king

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值