这题可以把“拿掉挡板”理解成:把两个相邻水池连起来。
连在一起的整段水池会混合成同一个水量,这个水量就是:

  • 这段总水量 / 这段水池个数

所以我们要维护两个东西:

  1. 哪些水池已经连成一段(连通块)
  2. 每段的“总水量”和“长度”

这正好是并查集能做的:

  • fa 维护连通块
  • sm 维护块内总水量
  • sz 维护块大小
  • 查询 2 i 时,输出 sm[root(i)] / sz[root(i)]

难点在操作 1 l r

它要删除区间 [l,r] 里所有挡板,也就是把边 (l,l+1),(l+1,l+2),...,(r-1,r) 全部连起来。
如果每次都暴力扫,会超时。

这里再加一个“跳指针并查集”(也可叫 next 数组):

  • nx[i] 表示“从 i 开始,下一块还没被删除的挡板位置”
  • 挡板 i 一旦删掉,就令 nx[i]=find(i+1),以后直接跳过

这样每块挡板最多只会被处理一次,总复杂度就降下来了。

整体复杂度:

  • 每个挡板最多删一次
  • 每次并查集合并/查找是近似常数(阿克曼反函数)

总复杂度是 O((n+m) * α(n))

#include<bits/stdc++.h>
using namespace std;

using ll=long long;
using ull=unsigned long long;
using ld=long double;
using pii=pair<int,int>;
using pll=pair<ll,ll>;
using vi=vector<int>;
using vvi=vector<vector<int>>;
using vll=vector<ll>;
using vvll=vector<vector<ll>>;
using vc=vector<char>;
using vs=vector<string>;
using vb=vector<bool>;
using vpii=vector<pii>;
using vpll=vector<pll>;

const int INF=1e9;
const ll LINF=4e18;
const int MOD=1e9+7;
const int MOD2=998244353;

#define IOS ios::sync_with_stdio(false); cin.tie(nullptr);
#define endl '\n'
#define all(x) x.begin(),x.end()
#define ral(x) x.rbegin(),x.rend()
#define fi first
#define se second
#define fix(x) fixed<<setprecision(x)

ll gcd(ll a,ll b){
	return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
	return a/gcd(a,b)*b;
}

ll qpow(ll a,ll b,ll mod=MOD){
	ll res=1;
	a%=mod;
	while(b){
		if(b&1)res=res*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return res;
}

ll modinv(ll a,ll p=MOD){
	return qpow(a,p-2,p);
}

struct Node{
	int a,b;
	
	bool operator<(const Node &y)const{
		return b>y.b;
	}
};

struct DS{
    vi f,sz,nx;
    vll sm;

    void init(int n,const vll &a){
        f.resize(n+1);
        sz.assign(n+1,1);
        sm.assign(n+1,0);
        nx.resize(n+1);
        for(int i=1;i<=n;++i){
            f[i]=i;
            sm[i]=a[i];
            nx[i]=i;
        }
    }

    int fd(int x){
        while(f[x]!=x){
            f[x]=f[f[x]];
            x=f[x];
        }
        return x;
    }

    int fn(int x){
        int y=x;
        while(nx[y]!=y)y=nx[y];
        while(nx[x]!=x){
            int t=nx[x];
            nx[x]=y;
            x=t;
        }
        return y;
    }

    void mg(int x,int y){
        x=fd(x);
        y=fd(y);
        if(x==y)return;
        if(sz[x]<sz[y])swap(x,y);
        f[y]=x;
        sz[x]+=sz[y];
        sm[x]+=sm[y];
    }
};

void solve(){
    int n,m;cin>>n>>m;
    vll a(n+1);
    for(int i=1;i<=n;++i)cin>>a[i];

    DS d;
    d.init(n,a);

    cout<<fix(10);
    for(int i=1;i<=m;++i){
        int op;cin>>op;
        if(op==1){
            int l,r;
            cin>>l>>r;
            for(int j=d.fn(l);j<r;j=d.fn(j+1)){
                d.mg(j,j+1);
                d.nx[j]=d.fn(j+1);
            }
        }else{
            int x;
            cin>>x;
            int r=d.fd(x);
            cout<<(ld)d.sm[r]/d.sz[r]<<endl;
        }
    }
}

int main(){
	IOS;
	int _=1;//cin>>_;
	while(_--){
		solve();
	}
	return 0;
}