为了能到远方,脚下的每一步都不能少.|

园龄:粉丝:关注:

小笨的蓄水池

题目描述

小苯有 ( n ) 个水池,编号从 1 到 ( n ),每个水池中有一定的水量 ( ai )。水池之间有隔板,初始状态下这些隔板将水池隔开。

小苯需要进行两种操作:

移除隔板:操作格式为 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;    
}

本文作者:归游

本文链接:https://www.cnblogs.com/guiyou/p/18526247

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   归游  阅读(11)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起