• 2019牛客多校第七场E Find the median 权值线段树+离散化


    Find the median

    题目链接:

    https://ac.nowcoder.com/acm/contest/887/E

    题目描述

    Let median of some array be the number which would stand in the middle of this array if it was sorted beforehand. If the array has even length let median be smallest of of two middle elements. For example, median of the array ([10,3,2,3,2]) is 3 (i.e. ([2,2,underline{3},3,10])). Median of the array [1,5,8,1] is 1 (i.e. ([1,underline{1},5,8])).

    At first, you're given an empty sequence. There are N operations. The i-th operation contains two integers (L_i) and (R_i). This means that adding (R_i-L_i+1) integers (L_i, L_i+1, ... , R_i) into the sequence. After each operation, you need to find the median of the sequence.

    输入描述:

    The first line of the input contains an integer (N (1 leq N leq 400000)) as described above.

    The next two lines each contains six integers in the following format, respectively:

    • (X_1 X_2 A_1 B_1 C_1 M_1)
    • (Y_1 Y_2 A_2 B_2 C_2 M_2)

    These values are used to generate (L_i, R_i) as follows:

    We define:

    • (X_i = (A_1 imes X_{i-1} + B_1 imes X_{i-2} + C_1) module M_1), for (i= 3 to N)
    • (Y_i = (A_2 imes Y_{i-1} + B_2 imes Y_{i-2} + C_2) module M_2), for (i = 3 to N)

    We also define:

    • (L_i = min(X_i, Y_i) + 1), for (i = 1 to N).
    • (R_i = max(X_i, Y_i) + 1), for (i = 1 to N).

    Limits:
    (1 leq N leq 400000)
    (0 leq A_1 < M_1)
    (0 leq A_2 < M_2)
    (0 leq B_1 < M_1)
    (0 leq B_2 < M_2)
    (0 leq C_1 < M_1)
    (0 leq C_2 < M_2)
    (0 leq X_1 < M_1)
    (0 leq X_2 < M_1)
    (0 leq Y_1 < M_2)
    (0 leq Y_2 < M_2)
    (1 leq M_1 leq 10^9)
    (1 leq M_2 leq 10^9)

    输出描述:

    You should output lines. Each line contains an integer means the median.

    样例输入

    5
    3 1 4 1 5 9
    2 7 1 8 2 9

    样例输出

    3
    4
    5
    4
    5

    说明

    L = [3, 2 ,4, 1, 7]
    R = [4, 8, 8, 3, 9]

    题意

    给你一个空序列,(n)条指令,每次给你(l,r) ,表示向序列中加入(l,l+1,cdots,r) 总共(r-l+1)个元素,每条指令后输入序列的中位数。

    (n)条指令按题目所给的方法生成。

    题解

    这题如果不用离散的话,直接上权值线段树,这里着重讲一下离散的问题。

    离散时我开始觉得很不能理解的地方:

    1. 什么时候左闭右开

    2. 什么时候右端点+1

    3. 什么时候右端点-1

    我们不妨先来想一组数据:插入((1,1) (1,5) (5,5))

    如果按照普通离散是不是离散后就是((1,1) (1,2) (2,2))

    再用普通线段树,那么会发现((1,1)+(2,2))((1,2))效果一样,也就是中间的点没了,为什么呢?

    就是因为离散后我们没法判断某个点是左端点还是右端点还是中间点,导致两点间隙无法判断。

    我的处理方法:

    1. 将离散的点连起来变成求线段长度,比如求((1,5))改成求((1,6))这条线段的长度(()都是(5))
    2. 线段树每个节点((l,r)),实际管理区间是((l,r+1))
    3. 加入线段时,记得右端-1,因为线段树会往右多管理一个点

    这样((1,1) (1,5) (5,5)) 就变成了((1,2) (1,6) (5,6)),离散后再变成((1,2) (1,4) (3,4)),记得加入时右端点-1,即((1,1) (1,3) (3,3))这几个区间权值+1。

    (ps:) 这种区间覆盖问题很多都是要考虑端点的问题。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define INF 0x7f7f7f7f
    #define N 800050
    template<typename T>void read(T&x)
    {
        ll k=0; char c=getchar();
        x=0;
        while(!isdigit(c)&&c!=EOF)k^=c=='-',c=getchar();
        if (c==EOF)exit(0);
        while(isdigit(c))x=x*10+c-'0',c=getchar();
        x=k?-x:x;
    }
    void read_char(char &c)
    {while(!isalpha(c=getchar())&&c!=EOF);}
    ll n,num;
    ll X[N],Y[N],kth[N];
    struct Query{ll l,r;}que[N];
    struct Tree{ll l,r,lazy,sum;}tr[N<<2];
    void push_up(ll x)
    {
        ll len=kth[tr[x].r+1]-kth[tr[x].l];
        if (tr[x].l==tr[x].r)tr[x].sum=0;
        else tr[x].sum=tr[x<<1].sum+tr[x<<1|1].sum;
        tr[x].sum+=tr[x].lazy*len;
    }
    void push_down(ll x)
    {
        Tree &a=tr[x<<1],&b=tr[x<<1|1];
        a.lazy+=tr[x].lazy;
        b.lazy+=tr[x].lazy;
        tr[x].lazy=0;
        push_up(x<<1);
        push_up(x<<1|1);
    }
    void bt(ll x,ll l,ll r)
    {
        tr[x].lazy=tr[x].sum=0; tr[x].l=l; tr[x].r=r; 
        if (l==r)return;
        ll mid=(l+r)>>1;
        bt(x<<1,l,mid);
        bt(x<<1|1,mid+1,r);
    }
    void change(ll x,ll l,ll r)
    {
        if (l<=tr[x].l&&tr[x].r<=r)
        {tr[x].lazy++;push_up(x);return;}
        ll mid=(tr[x].l+tr[x].r)>>1;
        if (l<=mid)change(x<<1,l,r);
        if (mid<r)change(x<<1|1,l,r);
        push_up(x);
    }
    ll query(ll x,ll k)
    {
        if (tr[x].l==tr[x].r)return kth[tr[x].l]+(k-1)/tr[x].lazy;
        push_down(x);
        ll ls=tr[x<<1].sum;
        if (ls<k)return query(x<<1|1,k-ls);
        else return query(x<<1,k);
    }
    void work()
    {
        ll A1,B1,C1,A2,B2,C2,M1,M2,sum=0;
        read(n);
        read(X[1]); read(X[2]); read(A1); read(B1); read(C1); read(M1);
        read(Y[1]); read(Y[2]); read(A2); read(B2); read(C2); read(M2);
        for(ll i=3;i<=n;i++)X[i]=(A1*X[i-1]+B1*X[i-2]+C1)%M1;
        for(ll i=3;i<=n;i++)Y[i]=(A2*Y[i-1]+B2*Y[i-2]+C2)%M2;
        for(ll i=1;i<=n;i++)
        {
            que[i].l=min(X[i],Y[i])+1;
            que[i].r=max(X[i],Y[i])+2;
            kth[++num]=que[i].l;
            kth[++num]=que[i].r;
        }
        sort(kth+1,kth+num+1);
        num=unique(kth+1,kth+num+1)-kth-1;
        bt(1,1,num);
        for(ll i=1;i<=n;i++)
        {
            ll l=lower_bound(kth+1,kth+num+1,que[i].l)-kth;
            ll r=lower_bound(kth+1,kth+num+1,que[i].r)-kth;
            sum+=que[i].r-que[i].l;
            change(1,l,r-1);
            printf("%lld
    ",query(1,(sum+1)/2));
        }
        
    }
    signed main()
    {
    #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
    #endif
        work();
    }
    
  • 相关阅读:
    正则表达式match方法和search方法
    正则表达式(基础篇1)
    动画
    重绘和重排(回流)
    数组常用的10个方法
    css3只需一招,将网站变成灰色的
    Python-类的几种调用方法
    Codeforces Global Round 8 C. Even Picture(构造)
    Codeforces Global Round 8 D. AND, OR and square sum(位运算)
    Codeforces Round #650 (Div. 3) C. Social Distance
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/11514991.html
Copyright © 2020-2023  润新知