P3987 我永遠喜歡珂朵莉~ / P5610 [Ynoi2013] 大學
阿新 • • 發佈:2021-08-14
這個和 P4145 上帝造題的七分鐘 2 / 花神遊歷各國非常相像。同樣只需要 \(\log n\) 次修改就能讓一個數變成 \(0\)。
單點修改,區間查詢珂以簡單地用 BIT 解決。
考慮怎麼維護需要修改的數。珂以可能的每一個因子都維護一個數據結構,要修改的時候直接在該數字對應的資料結構裡面查詢有哪些要修改的。
因為一個數的因數最多 \(\sqrt{n}\) 個,而 \(1\le a_i\le 5\times10^5\)。所以如果資料結構的空間為 \(O(n)\),那麼總空間就為 \(n\sqrt{n}\),不會爆。
這個資料結構需要維護什麼操作?
-
二分。
-
刪除一個點。
-
一個點的值。
平衡樹當然珂以維護,但是這是 Ynoi。模仿 P4145,使用一個並查集維護一個數後面第一個合法的數。
初版程式碼:(MLE)
YJX AK IOI#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; }