Online games
https://atcoder.jp/contests/abc221/tasks/abc221_d
题目大意:给出 n n n 个人的区间,表示这人在这个区间时间内会登录游戏,现在请输出 n n n 个数 k i k_i ki ,表示有恰好 k i k_i ki 个人登录游戏的天数。
这种多区间和交并有点关系的问题就可以往扫面线的思想去靠一靠。那么我们利用扫描线的思想,处理出每个变化点,也就是 a i a_i ai 点此时区间会加一, a i + b i a_i+b_i ai+bi 点此时区间会减一。那么我们现在假定两个相邻变化点 i i i , j j j ,我们会发现 [ i , j ) [i,j) [i,j) 的登录总人数是不会变的,因为这中间没有任何变化点,登录人数不会变化。所以我们只要将变化点排序,然后去遍历变化点 i i i ,维护到此变化点 i i i 的时候尚存的区间个数(登录总人数) c n t cnt cnt ,再利用与后一个相邻点 j j j 的距离更新答案。注意遍历变化点的时候最后最后一个变化点不需要遍历到,因为它没有后一个相邻点。这样实际上将所有有人登录的区间都计算到了,所以最后输出答案即可。
#include <bits/stdc++.h>
using namespace std;
const int N = 4e5 + 10;
int n, len, ans[N];
pair<int, int> seg[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w" ,stdout);
#endif
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
int l, r; scanf("%d%d", &l, &r);
seg[++len] = {l, 1};
seg[++len] = {l + r, -1};
}
sort(seg + 1, seg + 1 + len);
int cnt = 0;
for (int i = 1; i < len; ++i) {
cnt += seg[i].second;
ans[cnt] += seg[i + 1].first - seg[i].first;
}
for (int i = 1; i <= n; ++i) {
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
}
一开始其实是脑瘫码了个线段树的。。。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4e5 + 10;
int n, len, t[N], ans[N];
ll sum[N << 5], lz[N << 5];
int lson[N << 5], rson[N << 5], root, tot;
pair<int, int> seg[N];
void update(int &rt, int l, int r, int L, int R) {
if (!rt) rt = ++tot;
sum[rt] += min(r, R) - max(l, L) + 1;
if (L <= l && r <= R) {
lz[rt]++;
return ;
}
int mid = (1ll* l + r) >> 1ll;
if (mid >= L) update(lson[rt], l, mid, L, R);
if (mid < R) update(rson[rt], mid + 1, r, L, R);
}
ll query(int rt, int l, int r, int L, int R) {
if (!rt) return 0;
if (L <= l && r <= R) return sum[rt];
ll ans = (min(r, R) - max(l, L) + 1) * lz[rt];
int mid = (1ll * l + r) >> 1ll;
if (mid >= L) ans += query(lson[rt], l, mid, L, R);
if (mid < R) ans += query(rson[rt], mid + 1, r, L, R);
return ans;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d", &n);
for (int i = 1; i <= n; ++i) {
scanf("%d%d", &seg[i].first, &seg[i].second);
t[++len] = seg[i].first; t[++len] = seg[i].first + seg[i].second - 1;
update(root, 1, 2e9, seg[i].first, seg[i].first + seg[i].second - 1);
}
sort(t + 1, t + 1 + len);
len = unique(t + 1, t + 1 + len) - t - 1;
ans[query(root, 1, 2e9, t[1], t[1])]++;
for (int i = 2; i <= len; ++i) {
int L = t[i - 1] + 1, R = t[i] - 1;
if (L <= R) {
ans[query(root, 1, 2e9, L, R) / (R - L + 1)] += R - L + 1;
}
ans[query(root, 1, 2e9, t[i], t[i])]++;
}
for (int i = 1; i <= n; ++i) {
printf("%d%c", ans[i], i == n ? '\n' : ' ');
}
}