题意:按照一定的公式给出若干个$<l,r>$,每次往一个序列中加上l到r的数字,并输出中位数。
思路:需要将每个$区间$离散化,比如把$[1,2]$变成$[1,3)$,也就是$[1,2)$和$[2,3)$,这样做才能完整的表达区间,否则如[2,2]这样的区间就会出现问题。
所以我们将每一个$[l,r+1)$离散化,设$(x)$代表x离散化后的数字,每次更新的时候,右区间应该是$(r+1)-1$。比如原来只有一个区间$[2,3]$,我们表示成$[2,4)$,离散化后我们更新的区间是$[1,1]$,加的数字的个数是$ve[2]-ve[1]$,ve是原数组。
查询和更新思路一样。
#include<bits/stdc++.h> #define clr(a,b) memset(a,b,sizeof(a)) #define pb(a) push_back(a) #define rep(i,x,n) for(int i=x;i<=n;++i) #define dep(i,n,x) for(int i=n;i>=x;--i) using namespace std; typedef long long ll; int n,m; const int inf=0x3f3f3f3f; const int maxn=4e5+10; ll x[maxn],y[maxn],A1,B1,C1,M1,A2,B2,C2,M2; vector<ll >ve; ll sz[maxn<<3],lazy[maxn<<3]; void add(int o,int l,int r,ll f){ sz[o]+=(ve[r+1]-ve[l])*f; lazy[o]+=f; } void pushdown(int o,int l,int r){ if(!lazy[o]||l==r)return; int mid=(l+r)>>1; add(o<<1,l,mid,lazy[o]); add(o<<1|1,mid+1,r,lazy[o]); lazy[o]=0; } void update(int o,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ add(o,l,r,1); return; } int mid=(l+r)>>1; pushdown(o,l,r); if(ql<=mid)update(o<<1,l,mid,ql,qr); if(mid<qr)update(o<<1|1,mid+1,r,ql,qr); sz[o]=sz[o<<1]+sz[o<<1|1]; } ll query(int o,int l,int r,int num){ if(l==r){ ll tot=sz[o]/(ve[l+1]-ve[l]); return ve[l]+(num-1)/tot; } pushdown(o,l,r); int mid=(l+r)>>1; if(sz[o<<1]>=num)return query(o<<1,l,mid,num); return query(o<<1|1,mid+1,r,num-sz[o<<1]); } int main(){ int n; 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); rep(i,3,n){ x[i]=(A1*x[i-1]+B1*x[i-2]+C1)%M1; y[i]=(A2*y[i-1]+B2*y[i-2]+C2)%M2; } rep(i,1,n){ x[i]++,y[i]++; if(x[i]>y[i]) swap(x[i],y[i]); ve.push_back(x[i]); ve.push_back(y[i]+1); } sort(ve.begin(),ve.end()); ve.erase(unique(ve.begin(),ve.end()),ve.end()); int cnt=ve.size(); rep(i,1,n){ x[i]=lower_bound(ve.begin(),ve.end(),x[i])-ve.begin(); y[i]=lower_bound(ve.begin(),ve.end(),y[i]+1)-ve.begin(); update(1,0,cnt,x[i],y[i]-1); printf("%lld ",query(1,0,cnt,(sz[1]+1)/2)); } }