2019牛客多校第七场 E Find the median(线段树区间化点)题解

题意:

传送门

有一个空的队列,有\(n( n<= 4e5)\)次操作,每次操作会得到一个\(L_i,R_i\),将\(L_i,L_{i+1} \cdots R_{i-1},R_i\)放进队列,每次询问此时队列的中位数。

思路:

因为\(L\)\(R\)的数量比较少,我们把所有\(L\)\(R\)的点离散化,如果任意两个点之间还有区间我们就再加一个点表示这个区间,那么我们显然可以得到,每一个点所代表的区间的数量都是相同的,那么只要用线段树维护,然后找区间第\(k\)大即可。最终的点最多为\(4e5 * 2 * 2\),空间花费\(16e5 * 4 * 2 * 8\ byte\),勉强够用。可能有些地方需要优化空间。

代码1:

#include<map>
#include<set>
#include<cmath>
#include<cstdio>
#include<stack>
#include<ctime>
#include<vector>
#include<queue>
#include<cstring>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<unordered_map>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const int maxn = 16e5 + 5;
const ll MOD = 998244353;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
struct Node{
    int l, r;
}q[maxn];
vector<int> vv, order;
ll num[maxn << 2];
int lazy[maxn << 2];
Node sz[maxn << 2], qujian[maxn];
void pushdown(int rt){
    if(lazy[rt]){
        num[rt << 1] += lazy[rt] * (sz[rt << 1].r - sz[rt << 1].l + 1LL);
        num[rt << 1 | 1] += lazy[rt] * (sz[rt << 1 | 1].r - sz[rt << 1 | 1].l + 1LL);
        lazy[rt << 1] += lazy[rt];
        lazy[rt << 1 | 1] += lazy[rt];
        lazy[rt] = 0;
    }
}
void pushup(int rt){
    num[rt] = num[rt << 1] + num[rt << 1 | 1];
}
void build(int l, int r, int rt){
    num[rt] = lazy[rt] = 0;
    if(l == r){
        sz[rt] = qujian[l];
        return;
    }
    int m = (l + r) >> 1;
    build(l, m, rt << 1);
    build(m + 1, r, rt << 1 | 1);
    sz[rt].l = sz[rt << 1].l, sz[rt].r = sz[rt << 1 | 1].r;
}
void update(int L, int R, int l, int r, int rt){
    if(L <= l && R >= r){
        lazy[rt]++;
        num[rt] += (sz[rt].r - sz[rt].l + 1LL);
        return;
    }
    pushdown(rt);
    int m = (l + r) >> 1;
    if(L <= m)
        update(L, R, l, m, rt << 1);
    if(R > m)
        update(L, R, m + 1, r, rt << 1 | 1);
    pushup(rt);
}
int queryK(int l, int r, ll k, int rt){
    if(l == r){
        int pos = k / lazy[rt];
        return k % lazy[rt] == 0? sz[rt].l + pos - 1 : sz[rt].l + pos;
    }
    pushdown(rt);
    int m = (l + r) >> 1;
    ll Lnum = num[rt << 1];
    if(Lnum >= k)
        return queryK(l, m, k, rt << 1);
    else
        return queryK(m + 1, r, k - Lnum, rt << 1 | 1);
}
int x[maxn / 2], y[maxn / 2];
int main(){
//    freopen("1.txt", "w", stdout);
    int n;
    ll a1, b1, c1, m1, a2, b2, c2, m2;
    vv.clear();
    order.clear();
    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 = 1; i <= n; i++){
        if(i > 2){
            x[i] =  (a1 * x[i - 1] + b1 * x[i - 2] + c1) % m1;
            y[i] =  (a2 * y[i - 1] + b2 * y[i - 2] + c2) % m2;
        }
        q[i].l = min(x[i], y[i]) + 1;
        q[i].r = max(x[i], y[i]) + 1;
        vv.push_back(q[i].l), vv.push_back(q[i].r);
    }
    sort(vv.begin(), vv.end());
    vv.erase(unique(vv.begin(), vv.end()), vv.end());

    int cnt = 0;
    for(int i = 0; i < vv.size(); i++){ //线段树区间规划
        qujian[++cnt].l = vv[i], qujian[cnt].r = vv[i];
        order.push_back(vv[i]);
        if(i + 1 < vv.size() && vv[i + 1] - vv[i] > 1){
            qujian[++cnt].l = vv[i] + 1, qujian[cnt].r = vv[i + 1] - 1;
            order.push_back(vv[i] + 1);
        }
    }

    build(1, cnt, 1);

    int l, r;
    ll sum = 0;
    for(int i = 1; i <= n; i++){
        l = lower_bound(order.begin(), order.end(), q[i].l) - order.begin() + 1;
        r = lower_bound(order.begin(), order.end(), q[i].r) - order.begin() + 1;
        update(l, r, 1, cnt, 1);
        sum += q[i].r - q[i].l + 1;
        printf("%d\n", queryK(1, cnt, (sum + 1) / 2, 1));
    }

    return 0;
}

posted @ 2019-08-09 15:33  KirinSB  阅读(256)  评论(0编辑  收藏  举报