JZOJ5879. 【NOIP2018提高组模拟9.22】电路图 B

在这里插入图片描述
在这里插入图片描述

题解

首先回忆一下初中物理知识,
两个电阻 R 1 , R 2 R_1,R_2 并联的后的电阻 R 1 R 2 / ( R 1 + R 2 ) R_1*R_2/(R_1+R_2)
考虑如何实现这个线段树标记,
如果是串联,就是直接加,非常方便。
但是标记要合并,要将两种标记实现合并,
设一个标记为(a,b,c,d)一个四元组。
表示x在这个标记之下变为了 x ( a x + b ) / ( c x + d ) x*(ax+b)/(cx+d)
于是很高兴地发现这个标记可以合并。

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;
}

猜你喜欢

转载自blog.csdn.net/lijf2001/article/details/82822814