P3987 我永远喜欢珂朵莉~ / P5610 [Ynoi2013] 大学
作者:互联网
这个和 P4145 上帝造题的七分钟 2 / 花神游历各国非常相像。同样只需要 \(\log n\) 次修改就能让一个数变成 \(0\)。
单点修改,区间查询珂以简单地用 BIT 解决。
考虑怎么维护需要修改的数。珂以可能的每一个因子都维护一个数据结构,要修改的时候直接在该数字对应的数据结构里面查询有哪些要修改的。
因为一个数的因数最多 \(\sqrt{n}\) 个,而 \(1\le a_i\le 5\times10^5\)。所以如果数据结构的空间为 \(O(n)\),那么总空间就为 \(n\sqrt{n}\),不会爆。
这个数据结构需要维护什么操作?
-
二分。
-
删除一个点。
-
一个点的值。
平衡树当然珂以维护,但是这是 Ynoi。模仿 P4145,使用一个并查集维护一个数后面第一个合法的数。
初版代码:(MLE)
#include<bits/stdc++.h>
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn=1e5+5;
struct ufs{
vector<int> fa;
vector<int> val;
int Find(int x){
if(x==fa.size()||fa[x]==x)return x;
return fa[x]=Find(x);
}
};//并查集
vector<ufs> e;
int n,m;
int a[maxn];
long long c[maxn],lst=0;
void add(int p,int x){
for(;p<=n;p+=p&-p)c[p]+=x;
}
long long query(int p){
long long res=0;
for(;p;p-=p&-p)res+=c[p];
return res;
}
int main(){
n=read(),m=read();
e.reserve(500005);
for(int i=1;i<=n;i++)a[i]=read(),add(i,a[i]);
for(int i=1;i<=n;i++){
for(int j=1;j*j<=a[i];j++){
if(a[i]%j==0){
e[j].val.push_back(i);
e[j].fa.push_back(e[j].fa.size());
if(j*j<a[i])e[a[i]/j].val.push_back(i),e[a[i]/j].fa.push_back(e[a[i]/j].fa.size());
}
}
}
for(int i=1;i<=m;i++){
int ch=read();
int l,r,x;
if(ch==1){
l=read(),r=read(),x=read();
l^=lst,r^=lst,x^=lst;
if(x==1)continue;
int nl=lower_bound(e[x].val.begin(),e[x].val.end(),l)-e[x].val.begin();
for(int j=e[x].Find(nl);j<e[x].val.size()&&e[x].val[j]<=r;j=e[x].Find(j+1)){
if(a[e[x].val[j]]%x==0){
add(e[x].val[j],-a[e[x].val[j]]);
add(e[x].val[j],a[e[x].val[j]]/x);
a[e[x].val[j]]/=x;
}
if(a[e[x].val[j]]%x!=0){
e[x].fa[j]=j+1;
}
}
}
if(ch==2){
// for(int i=1;i<=n;i++)cout<<a[i]<<" ";
// cout<<endl;
l=read(),r=read();
l^=lst,r^=lst;
lst=query(r)-query(l-1);
printf("%lld\n",lst);
}
}
return 0;
}
标签:ch,修改,int,P3987,Ynoi2013,fa,朵莉,维护,数据结构 来源: https://www.cnblogs.com/kkksc0100/p/15140510.html