小笨的蓄水池
题目描述
小苯有 ( 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;
}

浙公网安备 33010602011771号