B. Applejack and Storages
https://codeforces.com/contest/1393/problem/B
题意:给定n个木条,q个询问。4个长度相等的木条可以组成一个长方形,两对长度相等的木条可以组成一个矩形。q个询问中,可能拿去或者给予一个长度为x的木条,对于每个操作,判断当前拥有的木条能否组成一个正方形 + 一个矩形。
思路:先判断n个木条能组成多少个正方形,能组成多少对长度相等的木条。再对于每个操作,如果是增加了新的木条,看这次增加是否会增加正方形,或者增加木条对。如果是拿走木条,看正方形,或者木条对的数量是否减少。最后,对于每次询问,只要判断正方形的数量跟木条对的数量即可。
总结:思维惯性,第一次看到题目想到的解法是,对于每个木条长度,统计其数量,然后每次操作修改其数量,再去判断是否有正方形和矩形,但是这样存在一个缺点,就是不仅要有一个堆,这个堆需要按照木条的数量来构造,而且还要能实时根据这个堆中的value值来查找结点,并删除删除该节点,插入新的节点(删除节点修改木条数量后的节点),随后再看堆定跟第二大元素是否满足题意即可。但是C++库中只有优先队列,如果自己做一个这样的数据结构,理论上好像也是可行的。
写一个堆,满足优先队列的条件,堆中再维护一个红黑树,这个红黑树记录每个value值对应的节点编号,再节点上浮下浮移动的过程中,实时更新这个节点的位置即可,时间复杂度应该是O(logn * logn * n),感觉可行,最近两天如果有时间可以写个这样的数据结构试一下。
所以正确的思路引导,应该是:n个木条,先判断当前的情况-》对于每次修改木条,看看会对当前的木条造成什么影响?
inline void solve() {
int n;
cin >> n;
multiset<int> s;
multiset<int> e;
constexpr int limit = 1e5 + 10;
vector<int> a(limit);
for (int i = 0; i < n; ++i) {
int t;
cin >> t;
a[t] ++;
}
for (int i = 0; i < limit; ++i) {
if (a[i] >= 4) {
int t = a[i] / 4;
while (t --) {
s.insert(i);
}
if ((a[i] % 4) > 1) {
e.insert(i);
}
}
else if (a[i] > 1) {
e.insert(i);
}
}
int q;
cin >> q;
while (q --) {
char c;
int x;
cin >> c >> x;
if (c == '+') {
if (a[x] % 4 == 3) {
s.insert(x);
e.erase(e.find(x));
}
else if (a[x] & 1) {
e.insert(x);
}
a[x] ++;
}
else {
if (a[x] % 4 == 0) {
s.erase(s.find(x));
e.insert(x);
}
else if (a[x] % 2 == 0) {
e.erase(e.find(x));
}
a[x] --;
}
cout << (s.size() && (s.size() > 1 || e.size() >= 2) ? "YES\n" : "NO\n");
}
}

浙公网安备 33010602011771号