P7603 [THUPC2021] 鬼街 题解
P7603 [THUPC2021] 鬼街 题解
第一次见折半报警器的 trick,记录一下
首先观察到
接下来考虑询问,朴素的做法是:每一次灵异事件之后,都对所有监控器进行检验是否满足和为
这样复杂度不对,但是我们可以注意到并不是所有时刻都需要对某些监控器进行检验。
这里有一个显然但是关键的结论:
如果
反证法易证。
这启示我们,只在满足上必要条件的情况下,对于一个监控进行检验,检验之后更新限制为:
由于
那么我们只需要在每个位置上设置一个 "报警器",在单点设置监控/检验之后,为这个点添加 "报警器"
然后每次修改一个点的时候就对这个点上最可能报警的 "报警器" 进行检查,即限制最小的报警器。
这些报警器使用 std::set
或者 __gnu_pbds::tree
可以维护,但是常数略大,因为每次只需要取出最小值,可以使用一个堆来维护。
本题中询问
参考代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <ctime>
#include <ext/pb_ds/priority_queue.hpp>
#include <ext/pb_ds/assoc_container.hpp>
//#define int long long
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef pair<ll, int> PII;
const int N = 1e5 + 10;
int n, m, primes[N], tx[N], tot;
ll val[N], sback[N], a[N];
bool st[N];
void sieve() {
for(int i = 2; i < N; i ++) {
if(!st[i]) primes[++ tot] = i;
for(int j = 1; j <= tot && primes[j] * i < N; j ++) {
st[i * primes[j]] = 1;
if(i % primes[j] == 0) break;
}
}
}
__gnu_pbds::priority_queue<PII, greater<PII>, __gnu_pbds::pairing_heap_tag> warn[N];
vector<__gnu_pbds::priority_queue<PII, greater<PII>, __gnu_pbds::pairing_heap_tag>::point_iterator> back[N];
vector<int> que, pr[N];
void check(int i) {
ll s = 0, x = tx[i], y = val[i];
for(auto d : pr[x]) s += a[d];
y -= s - sback[i], val[i] = y;
for(int id = 0, d; id < pr[x].size(); id ++) d = pr[x][id], warn[d].erase(back[i][id]);
if(y <= 0) {
que.push_back(i);
return ;
}
ll lm = (y + (int)pr[x].size() - 1) / (int)pr[x].size();
sback[i] = s;
for(int id = 0, d; id < pr[x].size(); id ++) {
d = pr[x][id];
back[i][id] = warn[d].push({lm + a[d], i});
}
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n >> m, sieve();
clock_t stt =clock();
for(int i = 1; i <= tot; i ++)
for(int p = primes[i], j = p; j <= n; j += p)
pr[j].push_back(p);
int cnt = 0;
for(ll i = 1, op, x, y, lst = 0; i <= m; i ++) {
cin >> op >> x >> y, y ^= lst;
if(op == 1) {
cnt ++;
tx[cnt] = x, val[cnt] = y;
ll lm = (y + (int)pr[x].size() - 1) / (int)pr[x].size();
if(y == 0) que.push_back(cnt);
else {
back[cnt].resize(pr[x].size(), 0);
sback[cnt] = 0;
for(int id = 0, d; id < pr[x].size(); id ++) {
d = pr[x][id];
sback[cnt] += a[d];
back[cnt][id] = warn[d].push({lm + a[d], cnt});
}
}
}
else {
for(auto d : pr[x]) a[d] += y;
for(auto d : pr[x]) {
while(warn[d].size() && (warn[d].top().x <= a[d]))
check(warn[d].top().y);
}
sort(que.begin(), que.end());
cout << que.size() << ' ';
for(auto x : que) cout << x << ' '; cout << '\n';
lst = que.size();
que.clear();
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!