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 \times X_{i-1} + B_1 \times X_{i-2} + C_1)\ module\ M_1\), for \(i= 3\ to\ N\)
  • \(Y_i = (A_2 \times Y_{i-1} + B_2 \times 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\n",query(1,(sum+1)/2));
    }
    
}
signed main()
{
#ifndef ONLINE_JUDGE
    freopen("aa.in","r",stdin);
#endif
    work();
}

猜你喜欢

转载自www.cnblogs.com/mmmqqdd/p/11514991.html