题解: AT_abc391_d [ABC391D] Gravity
FlowerAccepted · · 题解
解题思路
注意到落下的正方形们满一行才会被消除,之后的正方形才会落下来。所以能清除多少行正方形和正方形们初始的高度无关,而是等于同一个
在加入一个绿色正方形后,最底部的一行才会被消除,如图
我们可以使用一个 vector<int>
具体的,可以按顺序输入到两个 pair<int, int> 数组
再将
bool cmp(pair<int, int> x, pair<int, int> y) {
return x.second < y.second;
}
再使用 sort(a + 1, a + n + 1, cmp) 进行排序。当然,你要愿意手搓
然后按顺序遍历
for (int i = 1; i <= n; i ++) {
v[a[i].first].push_back(a[i].second);
}
图
记
图
我们开一个大小为
这里 1e9+5 即可。
看不懂?上代码!
t.resize(maxs + 5); // 开大一点
for (int j = 1; j <= w; j ++) {
for (int i = 0; i < mins; i ++) {
t[i] = max(t[i], v[j][i]);
}
}
for (int i = mins; i < maxs; i ++) {
t[i] = 1e9 + 5;
}
还看不懂?上图片!
预处理完毕,开是处理询问。
对于每个询问,首先注意输入顺序。(编者被坑了!)
接着找到对应的正方形对应的层数 lower_bound 来优化,返回的是指针,注意减去开头:
id = (int)(lower_bound(v[b[A].first].begin(), v[b[A].first].end(), b[A].second) - v[b[A].first].begin());
然后注意到正方形若在
最后,根据预处理的结论,判断
这块内容如果不理解还请看看图
代码呈现
代码不丑,请参考。
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector> // 万能头不是 STL 成员,咱不用。
using namespace std;
pair<int, int> a[200005], b[200005];
vector<int> v[200005], t; // 防止越界,开大数组,从我做起
bool cmp(pair<int, int> x, pair<int, int> y) { // 比较数对
return x.second < y.second;
}
int main() {
int n, w, mins = 1e9+5, maxs = 0, q, A, T, id;
cin >> n >> w;
for (int i = 1; i <= n; i ++) {
cin >> b[i].first >> b[i].second;
a[i] = b[i];
} // 输入
sort(a + 1, a + n + 1, cmp);
for (int i = 1; i <= n; i ++) {
v[a[i].first].push_back(a[i].second);
} // 离散化??
for (int i = 1; i <= w; i ++) {
mins = min(mins, (int)v[i].size());
maxs = max(maxs, (int)v[i].size());
} // 计算层数
t.resize(maxs + 5);
for (int j = 1; j <= w; j ++) {
for (int i = 0; i < mins; i ++) {
t[i] = max(t[i], v[j][i]);
}
} // 计算每一层的消失时间
for (int i = mins; i < maxs; i ++) {
t[i] = 1e9 + 5;
} // inf
cin >> q;
for (int i = 1; i <= q; i ++) {
cin >> T >> A;
id = (int)(lower_bound(v[b[A].first].begin(), v[b[A].first].end(), b[A].second) - v[b[A].first].begin()); // 二分
cout << (T < t[id] ? "Yes\n" : "No\n"); // 换行!
}
return 0;
}
至此,本题 Accepted。
复杂度分析
预处理除排序外的均摊复杂度是