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

题目链接:https://ac.nowcoder.com/acm/contest/887/E

题意:给出L[i],R[i],每次添加L[i]...R[i],求出此时的中位数。

思路:因为添加的数范围为1e9,首先想到要用离散化,这里是用一个点来表示一个区间。

 

将右区间加一的主要目的是优化处理,将区间最后一个元素并入到前面,自己模拟一下就能明白啦。

然后用线段树维护每个节点所包含的元素个数,用懒惰标记laz表示加的次数,然后每次查询时若左子树的元素个数足够则在左子树查询,否则在右子树查询。

详见代码:

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

typedef long long LL;
const int maxn=4e5+5;

struct node{
    int l,r,laz;
    LL sz;
}tr[maxn<<3];

int n;
LL X[maxn],Y[maxn],A1,A2,B1,B2,C1,C2,M1,M2;
vector<int> vc;

void build(int v,int l,int r){
    tr[v].l=l,tr[v].r=r;
    if(l==r){
        return;
    }
    int mid=(l+r)>>1;
    build(v<<1,l,mid);
    build(v<<1|1,mid+1,r);
}

void pushdown(int v){
    tr[v<<1].sz+=(vc[tr[v<<1].r+1]-vc[tr[v<<1].l])*tr[v].laz;
    tr[v<<1].laz+=tr[v].laz;
    tr[v<<1|1].sz+=(vc[tr[v<<1|1].r+1]-vc[tr[v<<1|1].l])*tr[v].laz;
    tr[v<<1|1].laz+=tr[v].laz;
    tr[v].laz=0;
}

void update(int v,int l,int r){
    if(l<=tr[v].l&&r>=tr[v].r){
        tr[v].sz+=(vc[tr[v].r+1]-vc[tr[v].l]);
        tr[v].laz+=1;
        return;
    }
    if(tr[v].laz) pushdown(v);
    int mid=(tr[v].l+tr[v].r)>>1;
    if(l<=mid) update(v<<1,l,r);
    if(r>mid) update(v<<1|1,l,r);
    tr[v].sz=tr[v<<1].sz+tr[v<<1|1].sz;
}

int query(int v,LL k){
    if(tr[v].l==tr[v].r){
        int tmp=tr[v].sz/(vc[tr[v].l+1]-vc[tr[v].l]);
        return vc[tr[v].l]+(k-1)/tmp;
    }
    if(tr[v].laz) pushdown(v);
    if(k<=tr[v<<1].sz) return query(v<<1,k);
    else return query(v<<1|1,k-tr[v<<1].sz);
}

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]%M1+B1*X[i-2]%M1+C1)%M1;
        Y[i]=(A2*Y[i-1]%M2+B2*Y[i-2]%M2+C2)%M2;
    }
    for(int i=1;i<=n;++i){
        ++X[i],++Y[i];
        if(X[i]>Y[i]) swap(X[i],Y[i]);
        vc.push_back(X[i]),vc.push_back(Y[i]+1);
    }
    sort(vc.begin(),vc.end());
    vc.erase(unique(vc.begin(),vc.end()),vc.end());
    LL sum=0;
    int cnt=vc.size();
    build(1,0,cnt-1);
    for(int i=1;i<=n;++i){
        sum+=Y[i]-X[i]+1;
        int x,y;
        x=lower_bound(vc.begin(),vc.end(),X[i])-vc.begin();
        y=lower_bound(vc.begin(),vc.end(),Y[i]+1)-vc.begin();
        update(1,x,y-1);
        printf("%d\n",query(1,(sum+1)>>1));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/FrankChen831X/p/11349154.html