人,只有自己站起来,这个世界才能属于他|

园龄:粉丝:关注:

题解:[THUPC 2021] 鬼街

前言

不希望被称为减半报警器模板,因为它一不是减半,二就只有这一个题。

思路分析

考虑暴力,预处理出 x 的质因数集合,每次在对应位置上对所有报警器加,如果有一个炸了就删除它。

考虑优化方向,每次我们在对应位置单点修改,能不能对这个位置上的报警器合并处理?

问题是,我们每个报警器都牵连着它所有质因数集合位置的答案,使得每次修改影响的位置数很多,上界是 O(m)m 是报警器个数。

因此考虑将报警器拆分若干个,每一个均分血量,只有在某个报警器分身炸时再考虑这个报警器是否炸,如果没有炸,那么再次均分血量。

这样我们就独立了每个报警器,可以在每个位置上维护一个堆,做懒惰加懒惰删除即可。

现在我们分析一下复杂度。

每次报警器减半,血量至少减少至原来的 w(x)1w(x),因为 w(x)6,我们不妨就令 w(x)=6

每次减少时,需要 O(logn) 的代价来用堆维护修改。

因此,我们得到一个很松的复杂度上界是 O(nlognlog65v),需要一些常数优化才能通过。

代码实现

#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 中国大陆许可协议进行许可。

posted @   _Kenma  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起