APIO 2018题解
【Problem 1】
Statemant:
Solution:
发现这题有时间和位置两个维度,如果按位置排序似乎不太好做,于是考虑按时间排序。对于一个点,有效区间为\([a,b]\),可以把它拆成在\(a\)时间加人,在\(b+1\)时刻删除。问题变成了如何快速找出最小的\(len\)使得\([p-len,p+len]\)中包含所有种类的点。按照区间数颜色的套路,每个点记录一下往左走最先找到同颜色点的位置,为了方便,可以在最左边每种颜色各放一个点。于是查询一个区间的颜色转化成查询区间\([l,r]\)中有多少个点的信息小于\(l\)。根据单调性可以二分这个区间长度。查询颜色数的本质是二维数点,又因为二分强制在线,用数据结构维护复杂度应该不小于\(\log_2^2n\),再算上二分的复杂度大致是\(\mathcal O(n\log_2^3n)\)。考虑我们并不需要具体算出区间的颜色数,只需要知道这个颜色数是否等于颜色总数,于是考虑查询\([r+1,n]\)的信息最小值,如果小于\(l\),说明至少存在一个颜色没有被区间包括,这个查询可以用数据结构轻松实现。如果用线段树可以在线段树上做类似于线段树二分的操作,总时间复杂度可以做到\(\mathcal O(n \log_2 n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 3.5E5;
const int LIM = 2E8;
int seg[MAXN*20];
int lc[MAXN*20];
int rc[MAXN*20];
int ans[MAXN];
multiset <int> prePos[MAXN*20];
multiset <int> S[MAXN];
struct Node
{
int tim;
int pos;
int opt;
int kind;
int id;
Node() { tim = pos = opt = kind = id = 0; }
Node(int _t, int _p, int _o, int _k, int _id)
{
tim = _t, pos = _p, opt = _o, kind = _k, id = _id;
}
inline friend bool operator < (Node a, Node b)
{
if (a.tim != b.tim)
return a.tim < b.tim;
return a.opt < b.opt;
}
} ;
Node A[MAXN<<2];
int n, q, k, rt, totNode;
int p, v, t, curNum;
void upData(int& o, int l, int r)
{
if (!o)
o = ++totNode;
if (l == r)
{
if (t)
prePos[o].insert(v);
else
prePos[o].erase(prePos[o].find(v));
seg[o] = (prePos[o].empty()) ? LIM : (*prePos[o].begin());
return ;
}
int mid = l + r >> 1;
if (p <= mid)
upData(lc[o], l, mid);
else
upData(rc[o], mid + 1, r);
seg[o] = min(seg[lc[o]], seg[rc[o]]);
}
inline int getAns(int pos)
{
if (curNum < k)
return -1;
int l = 1;
int r = LIM;
int nowNode = rt;
int nowMin = LIM;
int tmpMin = LIM;
int mid;
while (l < r)
{
mid = l + r >> 1;
tmpMin = min(nowMin, seg[rc[nowNode]]);
if ((pos > mid) || (tmpMin < pos * 2 - mid))
l = mid + 1, nowNode = rc[nowNode];
else
nowMin = tmpMin, r = mid, nowNode = lc[nowNode];
}
return l - pos;
}
int main(void)
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> k >> q, seg[0] = LIM;
for (int i = 1;i <= k; ++i)
S[i].insert(-LIM), S[i].insert(LIM), p = LIM, v = -LIM, t = 1, upData(rt, 1, LIM);
int m = 0;
for (int i = 1;i <= n; ++i)
{
int a = 0, b = 0, c = 0, d = 0;
cin >> a >> b >> c >> d;
A[++m] = Node(c, a, 0, b, 0),
A[++m] = Node(d + 1, a, 1, b, 0);
}
for (int i = 1;i <= q; ++i)
{
int a = 0, b = 0;
cin >> a >> b;
A[++m] = Node(b, a, 2, 0, i);
}
sort(A + 1, A + 1 + m);
for (int i = 1;i <= m; ++i)
{
int o = A[i].opt;
int pos = A[i].pos;
int e = A[i].kind;
if (o == 0)
{
int limL = *--S[e].lower_bound(pos);
int limR = *S[e].lower_bound(pos);
p = limR, v = pos, t = 1, upData(rt, 1, LIM);
p = limR, v = limL, t = 0, upData(rt, 1, LIM);
p = pos, v = limL, t = 1, upData(rt, 1, LIM);
if (S[e].size() == 2)
++curNum;
S[e].insert(pos);
}
else
if (o == 1)
{
int limL = *--S[e].lower_bound(pos);
int limR = *++S[e].lower_bound(pos);
p = limR, v = pos, t = 0, upData(rt, 1, LIM);
p = limR, v = limL, t = 1, upData(rt, 1, LIM);
p = pos, v = limL, t = 0, upData(rt, 1, LIM);
if (S[e].size() == 3)
--curNum;
S[e].erase(S[e].find(pos));
}
else
ans[A[i].id] = getAns(pos);
}
for (int i = 1;i <= q; ++i)
cout << ans[i] << '\n';
return 0;
}

浙公网安备 33010602011771号