洛谷9695 [GDCPC 2023] Traveling in Cells 题解(线段树+二分)
考虑对于一个给定的颜色集合 \(S\),我们可达的位置一定是一个区间 \([L,R]\)。于是考虑怎么求出 \(L,R\) 即可。
考虑二分,现在问题转换成判定一个区间 \([x,R]\)(区间 \([L,x]\) 同理)是否所有颜色都在我们的集合 \(S\) 中。
考虑对每一个颜色开一个线段树。区间 \([x,R]\) 里的每个颜色都在集合 \(S\) 中,等价于 \(S\) 中所有颜色在 \([x,R]\) 里的出现次数之和为 \(R-x+1\)。
时间复杂度 \(O(n\log^2 n)\),如果实现的精细一点用线段树上二分可以做到 \(O(n \log n)\)。
const int MAXN = 1e5 + 5;
int n, q, c[MAXN], v[MAXN];
struct _sgt {
struct _node {
int v, ls, rs;
} tr[MAXN << 6];
int tot;
void pushup(int p) {
tr[p].v = tr[tr[p].ls].v + tr[tr[p].rs].v;
}
void modify(int &p, int l, int r, int k, int v) {
if (!p) p = ++tot;
if (l == r) return tr[p].v += v, void();
if (k <= mid) modify(tr[p].ls, l, mid, k, v);
else modify(tr[p].rs, mid + 1, r, k, v);
pushup(p);
}
int query(int p, int l, int r, int L, int R) {
if (!p) return 0;
if (L <= l && r <= R) return tr[p].v;
int res = 0;
if (L <= mid) res += query(tr[p].ls, l, mid, L, R);
if (mid < R) res += query(tr[p].rs, mid + 1, r, L, R);
return res;
}
void clear(int p) {
if (tr[p].ls) clear(tr[p].ls);
if (tr[p].rs) clear(tr[p].rs);
tr[p].v = tr[p].ls = tr[p].rs = 0;
}
} t;
int rt[MAXN];
int solveR(int x, int k, vector<int> a) {
int l = x, r = n + 1;
while (l + 1 < r) {
int sum = 0;
for (int i = 0; i < k; ++i)
sum += t.query(rt[a[i]], 1, n, x, mid);
if (sum == (mid - x + 1)) l = mid;
else r = mid;
}
return l;
}
int solveL(int x, int k, vector<int> a) {
int l = 0, r = x;
while (l + 1 < r) {
int sum = 0;
for (int i = 0; i < k; ++i)
sum += t.query(rt[a[i]], 1, n, mid, x);
if (sum == (x - mid + 1)) r = mid;
else l = mid;
}
return r;
}
struct _bit {
int tr[MAXN];
int lowbit(int x) { return x & (-x); }
void modify(int x, int v) {
while (x <= n) {
tr[x] += v;
x += lowbit(x);
}
}
int query(int x) {
int res = 0;
while (x) {
res += tr[x];
x -= lowbit(x);
}
return res;
}
} bit;
void work() {
cin >> n >> q;
for (int i = 1; i <= n; ++i)
cin >> c[i];
for (int i = 1; i <= n; ++i)
cin >> v[i];
for (int i = 1; i <= n; ++i) {
t.modify(rt[c[i]], 1, n, i, 1);
bit.modify(i, v[i]);
}
while (q--) {
int op; cin >> op;
if (op == 1) {
int p, x; cin >> p >> x;
t.modify(rt[c[p]], 1, n, p, -1);
t.modify(rt[x], 1, n, p, 1);
c[p] = x;
} else if (op == 2) {
int p, x; cin >> p >> x;
bit.modify(p, x - v[p]);
v[p] = x;
} else {
int x, k; cin >> x >> k;
vector<int> a(k);
for (int i = 0; i < k; ++i)
cin >> a[i];
int L = solveL(x, k, a), R = solveR(x, k, a);
cout << bit.query(R) - bit.query(L - 1) << endl;
}
}
for (int i = 1; i <= n; ++i) {
t.clear(rt[i]);
bit.tr[i] = 0;
}
fill(rt, rt + 1 + n, 0ll);
t.tot = 0;
}

浙公网安备 33010602011771号