题解
首先回忆一下初中物理知识,
两个电阻
并联的后的电阻
考虑如何实现这个线段树标记,
如果是串联,就是直接加,非常方便。
但是标记要合并,要将两种标记实现合并,
设一个标记为(a,b,c,d)一个四元组。
表示x在这个标记之下变为了
于是很高兴地发现这个标记可以合并。
code
#include <queue>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#include <time.h>
#define ll long long
#define N 500003
#define db long double
#define P putchar
#define G getchar
#define M ((l+r)>>1);
#define ls (x<<1)
#define rs (x<<1|1)
using namespace std;
char ch;
void read(int &n)
{
n=0;
ch=G();
while((ch<'0' || ch>'9') && ch!='-')ch=G();
ll w=1;
if(ch=='-')w=-1,ch=G();
while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
n*=w;
}
db max(db a,db b){return a>b?a:b;}
db min(db a,db b){return a<b?a:b;}
db mx[N*4],mi[N*4],ops,a[N*4],b[N*4],c[N*4],d[N*4];
int v[N],n,m,op,opl,opr,R;
db nxt(db x)
{
return(db)1.0/((db)1.0/x+(db)1.0/R);
}
void mix(int x,int y)
{
mx[x]=(mx[x]*a[y]+b[y])/(mx[x]*c[y]+d[y]);
mi[x]=(mi[x]*a[y]+b[y])/(mi[x]*c[y]+d[y]);
db aa,bb,cc,dd;
aa=a[x]*a[y]+c[x]*b[y];
bb=b[x]*a[y]+d[x]*b[y];
cc=a[x]*c[y]+c[x]*d[y];
dd=b[x]*c[y]+d[x]*d[y];
if(a[x]>10000000)a[x]=1,b[x]=bb/aa,c[x]=cc/aa,d[x]=dd/aa;
}
void down(int x)
{
mix(ls,x);mix(rs,x);
a[x]=d[x]=1;
b[x]=c[x]=0;
}
void work(int x,int l,int r)
{
if(l^r)down(x);
if(opl<=l && r<=opr)
{
if(op==3)a[x]=1,b[x]=R,c[x]=0,d[x]=1,mx[x]=mx[x]+R,mi[x]=mi[x]+R;
else a[x]=R,b[x]=0,c[x]=1,d[x]=R,mx[x]=nxt(mx[x]),mi[x]=nxt(mi[x]);
return;
}
int m=M;
if(opl<=m)work(ls,l,m);
if(m<opr)work(rs,m+1,r);
mx[x]=max(mx[ls],mx[rs]);
mi[x]=min(mi[ls],mi[rs]);
}
void find(int x,int l,int r)
{
if(l^r)down(x);
if(opl<=l && r<=opr)
{
if(op==1)ops=max(ops,mx[x]);else ops=min(ops,mi[x]);
return;
}
int m=M;
if(opl<=m)find(ls,l,m);
if(m<opr)find(rs,m+1,r);
}
void build(int x,int l,int r)
{
a[x]=d[x]=1;
b[x]=c[x]=0;
if(l==r)
{
mx[x]=mi[x]=v[l];
return;
}
int m=M;
build(ls,l,m);
build(rs,m+1,r);
mx[x]=max(mx[ls],mx[rs]);
mi[x]=min(mi[ls],mi[rs]);
}
int main()
{
freopen("b2.in","r",stdin);
freopen("b.out","w",stdout);
read(n);
for(int i=1;i<=n;i++)read(v[i]);
build(1,1,n);
read(m);
for(int i=1;i<=m;i++)
{
read(op);read(opl);read(opr);
if(op==1)
{
ops=-2147483647;
find(1,1,n);
printf("%.10lf\n",(double)ops);
}else
if(op==2)
{
ops=2147483647;
find(1,1,n);
printf("%.10lf\n",(double)ops);
}else read(R),work(1,1,n);
}
return 0;
}