这题可以把“拿掉挡板”理解成:把两个相邻水池连起来。
连在一起的整段水池会混合成同一个水量,这个水量就是:
- 这段总水量 / 这段水池个数
所以我们要维护两个东西:
- 哪些水池已经连成一段(连通块)
- 每段的“总水量”和“长度”
这正好是并查集能做的:
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;
}

京公网安备 11010502036488号