Find the median 2019牛客多校第七场 E

传送门:https://ac.nowcoder.com/acm/contest/887/E

考场上早点开这题就好了,到最后也没有过样例

主要还是离散化区间变成点的这种线段树题写的太少了,上次写可能是17年暑假卢总挂的题。。。

18年湖南省赛那道题也是离散化后要用一个点代表一个区间,然而当时就不敢写那题

赛后想清楚很快就改好了,但是因为进入线段树找恰好是中位数的地方出了一些问题,WA了一发。

首先把所有要加的区间的端点进行离散化,离散化后,每个端点中间加一个点表示中间间隔的区间,numval[i]表示每个节点所代表的区间的长度,如果是端点,那么为1,如果是端点之间的区间,那么就是num[i+1]-num[i]-1,(有可能为空)

因为空间为128M,且4e5个l,r,8e5个值,16e6个离散化节点,64e6个线段树节点,所以线段树不能记录节点的区间,只能记录sum和一个tag表示这个点所表示的区间完全被加+1了多少次。

用pre[i]表示前i个点的长度共有多少,那么在线段树add函数中,就可以直接计算出每个点的sum增加了多少。

我们通过计算得到当前一共有sum个数字,那么大小为res=(sum+1)/2大的数字就是中位数,那么进入线段树去二分,如果左儿子的sum严格小于当前的res,那么res-=tree[k<<1].sum,进入右儿子。这样可以保证最后找到的叶子节点一定是res<=tree[l].sum且res是严格大于0的(这里一开始没有这样判断所以WA了一发,以后注意),那么我们只要看这个叶子节点是区间还是端点,如果是区间,那么这个tree[l].tag直接就是这个区间一共被+1了多少次,那么这个区间中的每个数字的个数都是tree[l].tag,那么就可以计算出第res个数字是哪个了。

#include<bits/stdc++.h>
#define maxl 400010
using namespace std;
 
int n,cnt,tot,id,kk,nxtnum,ans;
int a1,a2,b1,b2,c1,c2,mod1,mod2;
int ax[maxl],ay[maxl],ll[maxl],rr[maxl];
int num[maxl*4],numval[maxl*4];
struct node
{
    long long sum;
    int tag;
}tree[maxl*4*4];
long long res;
long long pre[maxl*4];
 
inline void prework()
{
    scanf("%d",&n);
    scanf("%d%d",&ax[1],&ax[2]);
    scanf("%d%d%d%d",&a1,&b1,&c1,&mod1);
    scanf("%d%d",&ay[1],&ay[2]);
    scanf("%d%d%d%d",&a2,&b2,&c2,&mod2);
    ll[1]=min(ax[1],ay[1])+1;
    rr[1]=max(ax[1],ay[1])+1;
    ll[2]=min(ax[2],ay[2])+1;
    rr[2]=max(ax[2],ay[2])+1;
    for(int i=3;i<=n;i++)
    {
        ax[i]=(1ll*ax[i-1]*a1+1ll*ax[i-2]*b1+c1)%mod1;
        ay[i]=(1ll*ay[i-1]*a2+1ll*ay[i-2]*b2+c2)%mod2;
        ll[i]=min(ax[i],ay[i])+1;
        rr[i]=max(ax[i],ay[i])+1;
    }
    cnt=0;
    for(int i=1;i<=n;i++)
        num[++cnt]=ll[i],num[++cnt]=rr[i];
    sort(num+1,num+1+cnt);
    tot=unique(num+1,num+1+cnt)-num-1;
    num[tot+1]=num[tot];
    for(int i=1;i<=tot;i++)
    {
        numval[(i-1)*2+1]=1,numval[i*2]=num[i+1]-num[i]-1;
        pre[(i-1)*2+1]=pre[(i-1)*2]+1;
        pre[i*2]=pre[i*2-1]+numval[i*2];
    }
    for(int i=1;i<=n;i++)
    {
        id=lower_bound(num+1,num+1+tot,ll[i])-num;
        ll[i]=(id-1)*2+1;
        id=lower_bound(num+1,num+1+tot,rr[i])-num;
        rr[i]=(id-1)*2+1;
    }
}
 
inline void build(int k,int l,int r)
{
    int mid=(l+r)>>1;
    tree[k].tag=0;
    if(l==r)
    {
        tree[k].sum=tree[k].tag=0;
        return;
    }
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    tree[k].sum=tree[k<<1].sum+tree[k<<1|1].sum;
}
 
inline void gank(int k,int l,int r)
{
	int mid=(l+r)>>1;
    int d=tree[k].tag;
    if(d>0)
    {
        tree[k<<1].sum+=(pre[mid]-pre[l-1])*d;
        tree[k<<1].tag+=d;
        tree[k<<1|1].sum+=(pre[r]-pre[mid])*d;
        tree[k<<1|1].tag+=d;
        tree[k].tag=0;
    }
}
 
inline void add(int k,int l,int r,int l1,int r1)
{
    if(l1!=r1)
        gank(k,l1,r1);
    tree[k].sum+=(pre[r]-pre[l-1]);
    if(l==l1 && r==r1)
    {
        tree[k].tag+=1;
        return;    
    }
    int mid=(l1+r1)>>1;
    if(r<=mid)
        add(k<<1,l,r,l1,mid);
    else if(l>mid)
        add(k<<1|1,l,r,mid+1,r1);
    else
    {
        add(k<<1,l,mid,l1,mid);
        add(k<<1|1,mid+1,r,mid+1,r1);
    }
}
 
inline int query(int k,int l,int r)
{  
    if(l!=r)
        gank(k,l,r);
    if(l==r)
    {
        nxtnum=tree[k].tag;
        return l;
    }
    int mid=(l+r)>>1;
    if(tree[k<<1].sum<res)
    {
        res-=tree[k<<1].sum;
        query(k<<1|1,mid+1,r);
    }
    else
        query(k<<1,l,mid);
}
 
inline void mainwork()
{
    long long sum=0,tmp,k,z,y;
    build(1,1,tot*2);
    for(int i=1;i<=n;i++)
    {
        sum+=num[(rr[i]+1)/2]-num[(ll[i]+1)/2]+1;
        add(1,ll[i],rr[i],1,tot*2);
        res=(sum+1)/2;
        id=query(1,1,tot*2);
        if(id&1)
            ans=num[id/2+1]-1;
        else
            ans=num[id/2];
        ans+=res/nxtnum;
        if(res%nxtnum!=0)
            ans++;
        printf("%d\n",ans);
    }
}
 
int main()
{
    int t;
    prework();
    mainwork();
    return 0;
}

 

上一篇:线性基学习笔记(咕咕咕)


下一篇:2019牛客多校第四场 A meeting