$\quad $ 在解決區間問題時,如果直接修改或者線段樹不好維護且總共的有效修改很小時,我們就可以考慮使用並查集來解決問題。
$\quad $ 問題中的各元素需要滿足一定的條件,我們在遍歷的時候,如果當前元素修改完之後仍然滿足條件,那麼我們就可以直接跳到後面的位置後面第一個滿足條件的位置,反之,則將當前位置連到後面位置上即可。
一道簡單的線段樹問題
$\quad $ 觀察資料範圍可知(這裡沒有展示),每個數在被開方 \(6\) 次之後就會變成 \(1\) ,在變為 \(1\) 後對其開方無意義,所以我們可以使用並查集維護某位數字之後(包括這位數字)第一個需要開方的數字的位置,這樣就可以很快地跳到需要更改的位置,總的更改次數不超過 \(6n\) ,即可透過此題。
點選檢視程式碼
#define yhl 0
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=1e6+100;
int fa[N],a[N],n,m,l,r,c[N],k;
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int get_sum(int x){
if(!x)return yhl;
int ans=0;
while(x){ans+=c[x];x-=(x&-x);}
return ans;
}
void add(int x,int y){
if(!x)return;
while(x<=n){c[x]+=y;x+=(x&-x);}
}
signed main(){
scanf("%lld",&n);
for(int i=1;i<=n;i++){
fa[i]=i;
scanf("%lld",&a[i]);
add(i,a[i]);
}
fa[n+1]=n+1;
scanf("%lld",&m);
while(m--){
scanf("%lld%lld%lld",&k,&l,&r);
if(k)printf("%lld\n",get_sum(r)-get_sum(l-1));
else{
for(int i=find(l);i<=r;i=find(i)){
int op=(int)sqrt(a[i])-a[i];
add(i,op);
a[i]=sqrt(a[i]);
if(a[i]==1)fa[i]=i+1;
else i++;
}
}
}
return yhl;
}
$\quad $ 例題:白雪皚皚