题目链接: https://ac.nowcoder.com/acm/contest/887/E
题意:
给你n个区间,每次往你现有的数中加上l,l+1,.....,r-1,r这些数,问你每次加完这些数后你现在的数中的中位数是多少。
做法:
先将给你的数进行离散化,然后进行一番特殊的处理后就可以使用线段树了。什么特殊的处理呢,就是把右端点++,然后每次更新的时候只更新离散化后的 ,令每次结点更新的数都是(ve[r+1]-ve[l]+1)*倍数。laz延迟更新,保存的是每次加的次数即可。sz[rt]保存的是当前区间里有多少个数,然后我们在查询的过程中,如果左区间有的数sz[lson]大于我们要查的数的个数va,那么我们就在左区间里查,否则我们就在右区间里查第va-sz[lson]小的数就可以了。
可能有的人和我刚看到这个做法的时候一样的惊奇,老实说我不是第一次碰到这样的题了(第二次的说),所以我还是稍微写点东西记录一下这个做法,下次碰到的时候也好理解,不会理论分析,希望各位感性理解(是我感性理解得出的结果)。
我们假设要增加的区间是[3,8]和[5,9],第一件事要做的是扩充右区间,如下图,我们把数字3存放在3和4之间的那个位置,所以我们需要扩充右区间来保证数字空间的正确性,第二件事是,我们把所有的数保存在小于等于这个数的第一个数的位置上,即数字8存在数字5的位置上(因为右区间的扩充,其实就已经没有数字8了)。那么我们在加区间[3,8]的时候,其实是在(0,0)这个位置上加了2,在(1,1)这个位置上加了4,即把 3 4 加到了3的位置上,5 6 7 8加到了5的位置上,那么我们在查第3小的数的时候会跑到5这里差第一小的数,然后5+(1-1)=5就是答案了。
我们可以知道的是,同一个区间里面的每个数的个数都是一样的,比如我又加上了[5,9],那么在5这个和下一个数9差了4的位置上会有8个数,5 5 6 6 7 7 8 8,即我们要得到这里有多少数后除掉就好了。比如要查这里第4小的数,那么我们就是5+(4-1)/2等于6,因为每个数都有两个嘛。
自认为已经讲的算是清楚了吧,不懂的话再戳就好了(我尽力回答咳咳)。
#include
#define lson rt<<1
#define rson rt<<1|1
#define rep(i,a,b) for(int i=(int)a;i<=(int)b;i++)
using namespace std;
typedef pair pii;
typedef long long ll;
const int maxn=400005;
ll x[maxn],y[maxn],A1,A2,B1,B2,C1,C2,M1,M2;
ll sz[maxn*6],laz[maxn*6];
vector ve;
void deal(int rt,int l,int r,ll f){
sz[rt]+=(ve[r+1]-ve[l])*f; laz[rt]+=f;
}
void update(int l,int r,int rt,int ql,int qr){
if(ql<=l&&r<=qr){
deal(rt,l,r,1);
return ;
}
int mid=(r+l)/2;
if(laz[rt]){
deal(lson,l,mid,laz[rt]);
deal(rson,mid+1,r,laz[rt]);
laz[rt]=0;
}
if(ql<=mid) update(l,mid,lson,ql,qr);
if(qr>mid) update(mid+1,r,rson,ql,qr);
sz[rt]=sz[lson]+sz[rson];
}
ll query(int l,int r,int rt,ll va){
if(l==r){
int ti=sz[rt]/(ve[l+1]-ve[l]);
return ve[l]+(va-1)/ti;
}
int mid=(r+l)/2;
if(laz[rt]){
deal(lson,l,mid,laz[rt]);
deal(rson,mid+1,r,laz[rt]);
laz[rt]=0;
}
if(sz[lson]>=va) return query(l,mid,lson,va);
else return query(mid+1,r,rson,va-sz[lson]);
}
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());
ll sum=0;
int cnt=ve.size();
/*for(int i=0;i