P4848 崂山白花蛇草水 题解

单点修改,矩阵 kth,考虑树套树。

发现需要套三层,考虑怎么不写权值线段树套二维线段树。

用 KDT 代替掉两层数据结构即可。

KDT 套权值线段树是不可行的,因为 KDT 依赖 push up,需要权值线段树合并。

权值线段树套 KDT 是可行的,外层权值线段树上每个点维护一棵 KDT 表示对应值域区间内的点集。

查询时在外层权值线段树上二分即可。

时间复杂度 $O(n^{\frac32}\log V)$,空间复杂度 $O(n\log n)$。

#include <iostream>
#include <algorithm>
#define A 0.65
using namespace std;
struct T
{
    int l, r, x, y, s, D, L1, R1, L2, R2, V, Q;
    bool c();
    void u();
} z[5000050];
bool C1(int a, int b) { return z[a].x < z[b].x; }
bool C2(int a, int b) { return z[a].y < z[b].y; }
bool T::c() { return s * A <= max(z[l].s, z[r].s); }
void T::u()
{
    s = z[l].s + z[r].s + 1;
    Q = z[l].Q + z[r].Q + V;
    L1 = R1 = x;
    L2 = R2 = y;
    if (l)
        L1 = min(L1, z[l].L1),
        R1 = max(R1, z[l].R1),
        L2 = min(L2, z[l].L2),
        R2 = max(R2, z[l].R2);
    if (r)
        L1 = min(L1, z[r].L1),
        R1 = max(R1, z[r].R1),
        L2 = min(L2, z[r].L2),
        R2 = max(R2, z[r].R2);
}
int n, q, c, o, r, h, g[5000050];
void D(int x)
{
    if (x)
    {
        D(z[x].l);
        g[++g[0]] = x;
        D(z[x].r);
    }
}
int B(int s, int t)
{
    if (s > t)
        return 0;
    int m = s + t >> 1;
    double x1 = 0, x2 = 0, s1 = 0, s2 = 0;
    for (int i = s; i <= t; ++i)
        x1 += z[g[i]].x, x2 += z[g[i]].y;
    x1 /= t - s + 1;
    x2 /= t - s + 1;
    for (int i = s; i <= t; ++i)
        s1 += (z[g[i]].x - x1) * (z[g[i]].x - x1),
            s2 += (z[g[i]].y - x2) * (z[g[i]].y - x2);
    if (s1 > s2)
        nth_element(g + s, g + m, g + t + 1, C1), z[g[m]].D = 1;
    else
        nth_element(g + s, g + m, g + t + 1, C2), z[g[m]].D = 2;
    z[g[m]].l = B(s, m - 1);
    z[g[m]].r = B(m + 1, t);
    z[g[m]].u();
    return g[m];
}
void I(int &x, int v)
{
    if (!x)
        return x = v, z[x].u();
    if (z[x].D & 1)
        if (C1(v, x))
            I(z[x].l, v);
        else
            I(z[x].r, v);
    else if (C2(v, x))
        I(z[x].l, v);
    else
        I(z[x].r, v);
    z[x].u();
    if (z[x].c())
        g[0] = 0, D(x), x = B(1, g[0]);
}
int Q(int x, int l1, int r1, int l2, int r2)
{
    if (!x || l1 > z[x].R1 || r1 < z[x].L1 || l2 > z[x].R2 || r2 < z[x].L2)
        return 0;
    if (l1 <= z[x].L1 && z[x].R1 <= r1 && l2 <= z[x].L2 && z[x].R2 <= r2)
        return z[x].Q;
    return Q(z[x].l, l1, r1, l2, r2) + Q(z[x].r, l1, r1, l2, r2) + (l1 <= z[x].x && z[x].x <= r1 && l2 <= z[x].y && z[x].y <= r2 ? z[x].V : 0);
}
struct S{int l, r, o;}R[5000050];
void M(int l, int x, int y, int s, int t, int &p)
{
    z[++c].x = x;z[c].y = y;z[c].V = 1;I(R[p ? p : p = ++o].o, c);
    if(s == t) return;int m = s + t >> 1;
    if(l <= m) M(l, x, y, s, m, R[p].l);else M(l, x, y, m + 1, t, R[p].r);
}
int Q(int k, int l1, int r1, int l2, int r2, int s, int t, int p)
{
    if(s == t) return s;int m = s + t >> 1, o = Q(R[R[p].r].o, l1, r1, l2, r2);
    if(k <= o) return Q(k, l1, r1, l2, r2, m + 1, t, R[p].r);
    else return Q(k - o, l1, r1, l2, r2, s, m, R[p].l);
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> q;
    for(int i = 0, L = 0, o, l1, l2, r1, r2, k;i < q;++i)
    {
        cin >> o >> l1 >> l2 >> r1;
        l1 ^= L;l2 ^= L;r1 ^= L;
        if(o & 1) M(r1, l1, l2, 1, 1e9, h);
        else
        {
            cin >> r2 >> k;r2 ^= L;k ^= L;
            if(Q(R[h].o, l1, r1, l2, r2) < k)
                cout << "NAIVE!ORZzyz." << '\n', L = 0;
            else cout << (L = Q(k, l1, r1, l2, r2, 1, 1e9, h)) << '\n';
        }
    }
    return 0;
}
posted @ 2023-05-15 08:46  5k_sync_closer  阅读(7)  评论(0编辑  收藏  举报  来源