题解:P7603 [THUPC2021] 鬼街
题面
根据学长的讲题找到这里。
看懂了,记一下。
减半报警器。
考虑到如果
注意到
具体而言,我们假设一个警报器监视的集合为
具体实现就是对于每个质数维护一个堆来记录监测这里的所有监测器的阈值。每次更新后暴力取出所有阈值小于目前
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,ans;
bool f[100005];
vector<int>d[100005];
void ss(){//筛质数
for(int i=2;i<=100000;i++){
if(!f[i]){
for(int j=i;j<=100000;j+=i){
f[j]=1;
d[j].push_back(i);
}
}
}
}
struct node{
int val,id,tim;
bool operator<(const node &t)const{return val>t.val;}
};//记录一个加到堆中的阈值的值、对应的监测器以及是否失效
priority_queue<node>q[100005];
int las[100005],tag,num,cnt[100005],a[100005],b[100005],stp[100005];
vector<int>res,zer;
void Sol(node x){//检查一个监测器
int p=x.id;
if(las[p]==-1)return;//已报警
int sum=0;
for(int v:d[a[p]])sum+=cnt[v];//计算s
if(sum>=stp[p]+b[p]){//报警了
res.push_back(p);
las[p]=-1;
return;
}
b[p]=stp[p]+b[p]-sum;//更新阈值
stp[p]=sum;//当前值
las[p]=++tag;//现在使用最新的阈值
int s=d[a[p]].size(),l=(b[p]+s-1)/s;
for(int v:d[a[p]]){
q[v].push(node({cnt[v]+l,p,tag}));
}
}
void ch(int x){//检查一个堆
while(!q[x].empty()&&q[x].top().val<=cnt[x]){
node tmp=q[x].top();
q[x].pop();
if(las[tmp.id]!=tmp.tim)continue;//不是最新的
Sol(tmp);
}
}
signed main()
{
ss();
scanf("%lld%lld",&n,&m);
int op,x,y;
while(m--){
scanf("%lld%lld%lld",&op,&x,&y);
y^=ans;
if(op){
int s=d[x].size();
int l=(y+s-1)/s;
tag++;
num++;
if(y==0){
zer.push_back(num);
continue;
}
a[num]=x;
b[num]=y;
las[num]=tag;
for(int v:d[x]){
stp[num]+=cnt[v];
q[v].push(node({cnt[v]+l,num,tag}));
}
}
else{
res.clear();
for(int v:zer)res.push_back(v);
zer.clear();
for(int v:d[x])cnt[v]+=y;
for(int v:d[x])ch(v);
sort(res.begin(),res.end());
ans=res.size();
printf("%lld ",ans);
for(int v:res)printf("%lld ",v);
puts("");
}
}
return 0;
}