LGP5610 [Ynoi 2013] 大学 学习笔记
LGP5610 [Ynoi 2013] 大学 学习笔记
前言
本题解参考:这篇
题意简述
给定一个长为 \(n\) 的序列 \(A\)。需要支持以下两种操作:
1 l r x:把区间 \([l,r]\) 中所有满足 \(x|a_i\) 的 \(a_i\) 除以 \(x\)。2 l r x:问 \([l,r]\) 区间和。
强制在线。时间限制 \(\text{500ms}\)。
\(n,m\le 10^5\),\(1\le a_i,x\le 5\times 10^5\)。
做法解析
显然对于每个数来说操作一最多作用 \(\log V\) 次。所以整题就是个很暴力的东西。暴力改,树状数组查就是基本思路。我们要考虑的是如何快速找到每次修改操作影响的数。
首先,对于初始的状态,我们用调和级数的复杂度筛出每个数的所有因数。具体来说,我们对于每种数值 \(x\) 记录所有满足 \(a_i=x\) 的下标 \(i\),记这个集合为 \(C_i\)。然后枚举每个因数 \(i\) 和每个包含它作为因数的数 \(j\),\(\forall k\in C_j\),将 \(k\) 塞入集合 \(G_i\)。\(G_i\) 被实现为一个链表状物。这样对于一个询问,我们就找到 \(G_x\),暴力改里面的所有数,如果发现这个数失效了,就把它从链表里面删除。
这样子的复杂度是对的,因为一次删除对应查一个数的一个约数,查到的总次数肯定是 \(O(n\log V)\) 的,没查到的话就不会再查,而一个数的约数个数可以粗略认为是 \(\sqrt[3]{V}\) 的,所以没查到时耗费的总时间复杂度可以认为是 \(O(n\sqrt[3]{V})\) 的。
没啥好说了,看代码吧。
代码实现
有点卡常。
那个 init() 最后那个排序用 stable_sort() 跑得更快,可能和这个场景下很多元素相对有序有关(每次我们都是在加一条单增序列进去)。那个检测是否大于的特判确实也能卡常。
#include <bits/stdc++.h>
using namespace std;
using namespace obasic;
const int MaxN=1e5+5,MaxV=5e5+5;
int N,M,A[MaxN],Opt,X,Y,Z,V;lolo ans;
vector<int> G[MaxV],nxt[MaxV],C[MaxV];int siz[MaxV];
struct BinidTree{
int n;lolo t[MaxN];
void init(int x){n=x,fill(t,t+n+1,0);}
int lowbit(int x){return x&(-x);}
void add(int p,int x){for(;p<=n;p+=lowbit(p))t[p]+=x;}
lolo gts(int p){lolo res=0;for(;p;res+=t[p],p-=lowbit(p));return res;};
lolo getsum(int l,int r){return gts(r)-gts(l-1);}
}BiT;
void init(){
BiT.init(N);
for(int i=1;i<=N;i++)C[A[i]].push_back(i),BiT.add(i,A[i]);
for(int i=1;i<=V;i++){
for(int j=i;j<=V;j+=i){
for(int k : C[j])G[i].push_back(k),nxt[i].push_back(siz[i]),siz[i]++;
}
if(G[i].empty())continue;
for(int j=1;j<G[i].size();j++)if(G[i][j-1]>G[i][j]){stable_sort(G[i].begin(),G[i].end());break;}
}
}
int afind(vector<int> &vec,int k){return vec[k]==k||k>=vec.size()?k:vec[k]=afind(vec,vec[k]);}
void dele(int l,int r,int x){
if(x==1||G[x].empty())return;int s=lwberi(G[x],l);
for(int i=afind(nxt[x],s);i<G[x].size()&&G[x][i]<=r;i=afind(nxt[x],i+1)){
if(A[G[x][i]]%x==0){
int tmp=A[G[x][i]]/x;
BiT.add(G[x][i],tmp-A[G[x][i]]);
A[G[x][i]]=tmp;
}
if(A[G[x][i]]%x)nxt[x][i]=i+1;
}
}
int main(){
readis(N,M);
for(int i=1;i<=N;i++)readi(A[i]),maxxer(V,A[i]);
init();for(int i=1;i<=M;i++){
readis(Opt,X,Y);
X^=ans,Y^=ans;
if(Opt==1)readi(Z),Z^=ans,dele(X,Y,Z);
if(Opt==2)ans=BiT.getsum(X,Y),writil(ans);
}
return 0;
}
浙公网安备 33010602011771号