題目描述
小苯有 ( n ) 個水池,編號從 1 到 ( n ),每個水池中有一定的水量 ( \(a_i\) )。水池之間有隔板,初始狀態下這些隔板將水池隔開。
小苯需要進行兩種操作:
移除隔板:操作格式為 1 l r,表示將第 ( l ) 個水池和第 ( r ) 個水池之間的所有隔板移除。這意味著在這個範圍內的水池將會合並,水量會變成這些水池水量的平均值。
查詢水量:操作格式為 2 i,表示查詢第 ( i ) 個水池當前的水量。如果該水池的隔板已經被移除,它的水量將是合併後的平均值。
因此,題目的核心在於處理水池之間的隔板移除和水量查詢,確保在移除隔板後能夠正確計算和返回水量。
思路
這種資料的處理,沒有尋常的資料結構處理,但是,這種區間合併的操作,與並查集非常類似
並查集的思想在於,兩顆樹之間的合併,而這裡的區間亦可以進行類似的操作
移除隔板後,就將相鄰的區間合併(合併相鄰兩顆子樹),查詢時就查詢區間被合併到哪個區間了(類似於父節點)
CODE
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
struct node{
int l,r,cnt;
double sum;
}a[maxn];
int f[maxn];
int n,m;
int find(int x){
if(x!=f[x]) return f[x]=find(f[x]);
return x;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%lf",&a[i].sum);
a[i].l=a[i].r=i;
a[i].cnt=1;f[i]=i;
}
while(m--){
int op;scanf("%d",&op);
if(op==1){
int x,y;scanf("%d %d",&x,&y);
double ans=0;
for(int i=a[f[x]].r+1;i<=a[f[y]].l;++i){
if(find(x)==find(i)) continue;
int fx=find(x),fi=find(i);
f[fi]=fx;
a[fx].sum+=a[fi].sum;
a[fx].cnt+=a[fi].cnt;
a[fx].l=min(a[fx].l,a[fi].l);
a[fx].r=max(a[fx].r,a[fi].r);
}
}
else{
int x;scanf("%d",&x);
printf("%.12f\n",a[find(x)].sum*1.0/a[find(x)].cnt);
}
}
return 0;
}