题解:[THUPC 2021] 鬼街
前言
不希望被称为减半报警器模板,因为它一不是减半,二就只有这一个题。
思路分析
考虑暴力,预处理出 的质因数集合,每次在对应位置上对所有报警器加,如果有一个炸了就删除它。
考虑优化方向,每次我们在对应位置单点修改,能不能对这个位置上的报警器合并处理?
问题是,我们每个报警器都牵连着它所有质因数集合位置的答案,使得每次修改影响的位置数很多,上界是 , 是报警器个数。
因此考虑将报警器拆分若干个,每一个均分血量,只有在某个报警器分身炸时再考虑这个报警器是否炸,如果没有炸,那么再次均分血量。
这样我们就独立了每个报警器,可以在每个位置上维护一个堆,做懒惰加懒惰删除即可。
现在我们分析一下复杂度。
每次报警器减半,血量至少减少至原来的 ,因为 ,我们不妨就令 。
每次减少时,需要 的代价来用堆维护修改。
因此,我们得到一个很松的复杂度上界是 ,需要一些常数优化才能通过。
代码实现
#include<bits/stdc++.h>
using namespace std;
int n,m,op,x,dcnt,tot,sum,now[100005],p[100005],lstans;
long long cnt[100005],tag[100005],lst[100005][6],y;
vector<int> v[100005],ans;
inline void work(int x){
int a=x;
for(register int i=2;i*i<=a;i++){
if(a%i==0){
v[x].push_back(i);
while(a%i==0) a/=i;
}
}
if(a>=2) v[x].push_back(a);
}
struct node{
int id,tim;
long long val;
inline bool operator <(const node &a)const{
if(val!=a.val) return a.val<val;
else return a.id<id;
}
};
priority_queue<node> q[100005];
inline void add(int z,int x){
now[z]=++dcnt;
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
lst[z][i]=tag[y];
q[y].push((node){z,now[z],(cnt[z]+v[x].size()-1)/v[x].size()+tag[y]});
}
}
vector<int> t;
void solve(int z){
int x=p[z];
if(now[z]==-1) return;
for(int l=0;l<v[x].size();l++){
int y=v[x][l];
cnt[z]-=(tag[y]-lst[z][l]);
}
if(cnt[z]<=0){
now[z]=-1;
ans.push_back(z);
}else{
add(z,x);
}
}
inline void modify(int x,long long k){
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
tag[y]+=k;
}
t.clear();
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
while(q[y].size()){
node it=q[y].top();
if(it.val>tag[y]) break;
q[y].pop();
if(it.tim!=now[it.id]) continue;
solve(it.id);
}
}
}
signed main(){
//freopen("2.in.in","r",stdin);
//freopen("out.out","w",stdout);
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(register int i=2;i<=n;i++){
work(i);
}
for(register int i=1;i<=m;i++){
cin>>op>>x>>y;
y^=lstans;
if(op==0){
modify(x,y);
sort(ans.begin(),ans.end());
cout<<ans.size()<<' ';
for(int j=0;j<ans.size();j++){
cout<<ans[j]<<' ';
}
cout<<'\n';
lstans=ans.size();
ans.clear();
}else{
tot++;
if(!y){
ans.push_back(tot);
continue;
}
cnt[tot]=y;
p[tot]=x;
add(tot,x);
}
}
return 0;
}
本文作者:Kenma
本文链接:https://www.cnblogs.com/Kenma/p/18703445
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步