题目链接:https://ac.nowcoder.com/acm/contest/887/E
题意:给出一个空集合,每次给出一个l,r的区间将l,r的这些数全部扔进区间内,每次要求输出此时的中位数是多少,若是集合是偶数个数则输出小的那个中位数。
数据范围:1<=N,l,r<=4e5
思路:首先离散化一下,然后进行类似上一篇博客那样建树,及线段树的每个节点都是一个左闭右开的区间,那么对于每次插入数只需要找到对应的区间将数插入即可,此题的lazy标记只需要一直储存区间的和即可。每次在线段树上找中间大的数就好了。难点还是在于那个左闭右开不重不漏的建树。
#include<bits/stdc++.h>
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long ll;
const int N=4e5+5;
int n,m,t,cnt;
ll A1,A2,B1,B2,C1,C2,M1,M2,b[N<<1],x[N],y[N],sz[N<<3],lazy[N<<3];
void up(int rt,int l,int r,ll val){
sz[rt]+=(b[r+1]-b[l])*val;
lazy[rt]+=val;
}
void update(int rt,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
up(rt,l,r,1);
return ;
}
int mid=(l+r)>>1;
if(lazy[rt]){
up(ls,l,mid,lazy[rt]);
up(rs,mid+1,r,lazy[rt]);
lazy[rt]=0;
}
if(ql<=mid) update(ls,l,mid,ql,qr);
if(qr>mid) update(rs,mid+1,r,ql,qr);
sz[rt]=sz[ls]+sz[rs];
}
ll query(int rt,int l,int r,ll pos){
if(l==r){
int ti=sz[rt]/(b[l+1]-b[l]);
return b[l]+(pos-1)/ti;
///return b[l]-1+ceil(1.0*pos/ti);
}
int mid=(l+r)/2;
if(lazy[rt]){
up(ls,l,mid,lazy[rt]);
up(rs,mid+1,r,lazy[rt]);
lazy[rt]=0;
}
if(sz[ls]>=pos) return query(ls,l,mid,pos);
else return query(rs,mid+1,r,pos-sz[ls]);
}
int main(){
scanf("%d",&n);
scanf("%lld%lld%lld%lld%lld%lld",&x[1],&x[2],&A1,&B1,&C1,&M1);
scanf("%lld%lld%lld%lld%lld%lld",&y[1],&y[2],&A2,&B2,&C2,&M2);
for(int i=3;i<=n;i++){
x[i]=(A1*x[i-1]+B1*x[i-2]+C1)%M1;
y[i]=(A2*y[i-1]+B2*y[i-2]+C2)%M2;
}
for(int i=1;i<=n;i++){
if(x[i]>y[i])swap(x[i],y[i]);
x[i]++,y[i]++;
b[++cnt]=x[i],b[++cnt]=y[i]+1;
}
sort(b+1,b+cnt+1);
cnt=unique(b+1,b+cnt+1)-b-1;
ll sum=0;
for(int i=1;i<=n;i++){
sum+=(y[i]-x[i]+1);
x[i]=lower_bound(b+1,b+cnt+1,x[i])-b;
y[i]=lower_bound(b+1,b+cnt+1,y[i]+1)-b;
update(1,1,cnt-1,x[i],y[i]-1);
printf("%lld\n",query(1,1,cnt-1,(sum+1)/2));
}
return 0;
}