P5610 [Ynoi2013] 大学

题目

P5610 [Ynoi2013] 大学

分析

似乎是个简单题,容易想到势能分析,每一个点最多被除 \(\log\) 次。

于是问题变成快速找到一个数的所有倍数的位置。

直接对每一个数开一个 \(set\) 存其倍数集合,找到后可以判断是否删掉,也就是区间删除,可以并查集实现。

代码

#include<bits/stdc++.h>
using namespace std;
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
template <typename T>
inline void read(T &x){
	x=0;char ch=getchar();bool f=false;
	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	x=f?-x:x;
	return ;
}
template <typename T>
inline void write(T x){
	if(x<0) putchar('-'),x=-x;
	if(x>9) write(x/10);
	putchar(x%10^48);
	return ;
}
#define ll long long
const int N=5e5+5;
int n,m,a[N],cnt[N],Max,*d[N],node[N*605],*tp=node;
ll c[N],Ans;
inline void Add(int x,const ll v){for(;x<=n;x+=(x&(-x))) c[x]+=v;return ;}
inline ll Ask(int x){ll res=0;for(;x;x-=(x&(-x))) res+=c[x];return res;}
struct DSU{
	int *fa;
	inline void Init(const int n){for(register int i=0;i<n;i++) fa[i]=i;}
	inline int Getfa(int x){
		int t1,t2=x;
		while(x!=fa[x]) x=fa[x];
		while(t2!=fa[t2]) t1=fa[t2],fa[t2]=x,t2=t1; 
		return x;
	}
}nex[N];
inline void Modify(int l,int r,const int x){
	l=lower_bound(d[x],d[x]+cnt[x],l)-d[x];
	r=upper_bound(d[x],d[x]+cnt[x],r)-d[x]-1;
	if(l>r) return ;
	for(register int u=nex[x].Getfa(l);u<=r;u=nex[x].Getfa(u+1)){
		int t=d[x][u];
		if(a[t]%x==0) Add(t,a[t]/x-a[t]),a[t]/=x;
		if(u>=r) break;
		if(a[t]%x) nex[x].fa[u]=nex[x].Getfa(u+1);
	}
	return ;
}

int main(){
	read(n);read(m);
	for(register int i=1;i<=n;i++) read(a[i]),Add(i,a[i]),cnt[a[i]]++,Max=max(Max,a[i]);
	for(register int i=1;i<=Max;i++) for(int j=i+i;j<=Max;j+=i) cnt[i]+=cnt[j];
	for(register int i=1;i<=Max+1;i++) if(cnt[i]) d[i]=tp,tp+=cnt[i],nex[i].fa=tp,nex[i].Init(cnt[i]),tp+=cnt[i],cnt[i]=0;
	for(register int i=1;i<=n;i++) for(int j=1;j*j<=a[i];j++) if(a[i]%j==0){d[j][cnt[j]++]=i;if(j*j!=a[i]) d[a[i]/j][cnt[a[i]/j]++]=i;}
	int op,l,r,x;
	for(register int i=1;i<=m;i++){
		read(op);read(l);read(r);
		l^=Ans,r^=Ans;
		if(op==1){read(x);x^=Ans;if(x==1) continue;Modify(l,r,x);}
		else write(Ans=Ask(r)-Ask(l-1)),puts("");
	}
	return 0;
}
posted @ 2021-08-20 19:46  __Anchor  阅读(43)  评论(0编辑  收藏  举报