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;
}