Educational Codeforces Round 10 部分题解
两道线段题,都只差一步想出正解。差的这一步还都是我见过无数遍的套路。
脑子进水生锈了属于是。
C. Foe Pairs
题意简述
给定一个长为 \(n\) 的排列,再给定 \(m\) 的无序二元组 \((x, y)\),请计算有多少个区间满足不存在两个数都出现的二元组。
或者换个描述,给定一些线段,请计算有多少个区间满足没有一条线段被完整包含。
解题报告
很显然是对每一个点往左 / 往右处理点什么东西出来,然后累计答案。然后我就死活想不出怎么处理。
实际很简单,可以用一个类似差分的思想,先处理单点再前缀扫一遍:设 \(f(i)\) 表示位置 \(i\) 往左走到最远的地方是哪,很显然对于所有右端点在 \(r\) 的线段 \([l_i, r], f(r) = \max\{l_i + 1\}.\)
然后再做一个前缀 \(\max\),就可以知道所有的 \(f(i)\)(画个图就明白了)。之后再把每个位置的 \(i - f(i) + 1\) 加起来即可。
const int MAXN = 3e5 + 10;
int n, m;
int aa[MAXN];
std::pair<int, int> foe[MAXN];
std::pair<int, int> fpos[MAXN];
bool cmp(std::pair<int, int> x, std::pair<int, int> y) {
return x.se == y.se ? x.fi > y.fi : x.se < y.se;
}
int pos[MAXN];
int lst[MAXN];
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
n = read(); m = read();
rep (i, 1, n) pos[aa[i] = read()] = i;
rep (i, 1, m) {
foe[i].fi = pos[read()]; foe[i].se = pos[read()];
if (foe[i].fi > foe[i].se) std::swap(foe[i].fi, foe[i].se);
lst[foe[i].se] = std::max(lst[foe[i].se], foe[i].fi + 1);
}
lli ans = 0;
int x = 1;
for (int i = 1; i <= n; ++i) {
x = std::max(x, lst[i]);
ans += i - x + 1;
}
printf("%lld\n", ans);
return 0;
}
D. Nested Segments
题意简述
给定 \(n\) 条线段(端点不重合),求每条线段包含了多少线段。
解题报告
首先离散化。然后把线段随便按照某个端点排序,比如右端点吧。
考虑一个线段 \([L, R]\) 包含 \([l, r]\) 的充要条件是:\(L < l < r < R\),那么按照右端点排序之后,当前这条线段前面所有的线段都是满足 \(r < R\) 的,只需要查找有多少 \(L < l\)。这个东西显然是拿树状数组边插入边查询。
const int MAXN = 2e5 + 10;
int n;
struct Seg {int l, r, id;} segs[MAXN];
bool cmp(Seg x, Seg y) { return x.r < y.r; }
int cnt; std::vector<int> lisan;
struct BIT {
int seq[MAXN << 1];
#define lb(x) (x & (-x))
void mod(int x) { for (; x <= cnt; x += lb(x)) ++seq[x]; }
int qry(int x) {
int r = 0; for(; x; x -= lb(x)) r += seq[x];
return r;
}
int qrg(int x, int y) { return qry(y) - qry(x - 1); }
} bit;
int ans[MAXN];
int main() {
std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
n = read();
rep (i, 1, n) {
segs[i].l = read(); segs[i].r = read();
segs[i].id = i;
lisan.push_back(segs[i].l); lisan.push_back(segs[i].r);
} std::sort(ALL(lisan)); lisan.erase(std::unique(ALL(lisan)), lisan.end());
cnt = (int) lisan.size();
rep (i, 1, n) {
segs[i].l = std::lower_bound(ALL(lisan), segs[i].l) - lisan.begin() + 1;
segs[i].r = std::lower_bound(ALL(lisan), segs[i].r) - lisan.begin() + 1;
}
std::sort(segs + 1, segs + 1 + n, cmp);
for (int i = 1; i <= n; ++i) {
ans[segs[i].id] = bit.qrg(segs[i].l, segs[i].r);
bit.mod(segs[i].l);
}
rep (i, 1, n) printf("%d\n", ans[i]);
return 0;
}
E. Pursuit for Artifacts
见 Tarjan 杂题选讲。
F
我看不懂题解,这下脑子真生锈了