LGP5610 [Ynoi 2013] 大学 学习笔记

LGP5610 [Ynoi 2013] 大学 学习笔记

Luogu Link

前言

本题解参考:这篇

题意简述

给定一个长为 \(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;
}
posted @ 2025-05-14 15:30  矞龙OrinLoong  阅读(13)  评论(0)    收藏  举报