2019牛客暑期多校训练营(第七场)E Find the median —— 线段树求大数据中位数

This way

题意:

你一开始有一个空序列,每次在你的序列中塞入l-r中所有的值,并且问你现在你的序列的中位数是什么。

题解:

二分+线段树TLE。。。重算一遍才发现忘记将lower_bound的复杂度算进去了。
需要用两个数组维护:sum[]表示区间内值的个数,flag[]是延时标记,同时它如果延到叶子结点了是不会清空的,那么在这里就可以表示这个位置出现了多少次来用。我们将所有输入离散化,这时候就有一个问题:我怎么知道我要查询的位置出现了几次?它可以看做是和它左边第一个在输入中出现过的数字是相等的。为什么?因为如果这个数不可能是中位数,那么我们就不会查到他,如果它可能是,那么我们线段树是按照从小到大建树的,那么肯定会查到它或者它左边的值。
对于为什么rig要+2,因为在线段树中,如果直接维护离散化区间的值,就比如说原数组第三个位置是3,第4个位置是5,第5个位置是6,那么我们如果加入3-6,对于离散化的结果是不会变的,但是线段树里面就少了一个4的内容。但是如果直接维护a[r+1]-a[l]+1的话,那么push_down时会多加一次,所以我们直接用r+2,这样不会错

#include
using namespace std;
#define ll long long
#define pa pair
const int N=4e5+5;
ll x[N],y[N],a1,b1,c1,m1,a2,b2,c2,m2;
ll a[N*2],flag[N*2*4],sum[N*2*4],num[N*2*4];
void push_down(int l,int r,int root)
{
    if(!flag[root])
        return ;
    int mid=l+r>>1;
    sum[root<<1]+=(ll)(a[mid+1]-a[l])*flag[root];
    sum[root<<1|1]+=(ll)(a[r+1]-a[mid+1])*flag[root];
    flag[root<<1]+=flag[root];
    flag[root<<1|1]+=flag[root];
    flag[root]=0;
}
void update(int l,int r,int root,int ql,int qr)
{
    if(l>=ql&&r<=qr)
    {
        sum[root]+=(ll)a[r+1]-a[l];
        flag[root]++;
        return ;
    }
    push_down(l,r,root);
    int mid=l+r>>1;
    if(mid>=ql)
        update(l,mid,root<<1,ql,qr);
    if(mid>1;
    push_down(l,r,root);
    if(sum[root<<1]

你可能感兴趣的:(想法,线段树)