【nodgd电路图B】线段树维护函数变换
这种题现在只见过两次,每次都觉得还是很神奇的,,,主要还是我太弱了orz orz orz
网上找不到链接和文字题面(NK的同学可以做到哦),简述题意:现在有横着一排n个电阻(n<=2.5*10^5),现在有m个操作(m<=2.5*10^5),1查询区间最小,2查询区间最大,3给区间每一个电阻串联上一个电阻值为R电阻,4给区间的每一个电阻并联上一个电阻值为R电阻。
物理题orz orz orz,做出来感谢hdhd和OBlack大佬的提示与帮助。我们可以将其每次变换转换为一个函数,(Ax + B / Cx + D) ,然后如果先执行某个函数再执行某个函数,就是将第一个函数代入第二个函数中,显然又会得到一个同阶的函数(因为这是一个线性的函数),这就是一次函数变换。
显然,对于一个电阻串联上一个新的电阻(阻值为R)的函数应该为(A=1,B=R,C=0,D=1),同时对于并联函数应该是(A=R,B=0,C=1,D=R)这样就可以完美表达出变换了。
之后就是一个区间极大值和区间极小值,区间覆盖函数,lazy putdowm函数下去的线段树问题了。有个毒点,函数A,B,C,D可能在多次变换后会变得极大导致精度有鬼,所以我们完全可以将A调整成1,其他同时/A,将他们的数据范围拉回来。
对于这些函数变换题的函数形式不是卡死的,就比如这次就是分式,所以应该及时调整思维。
code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn = 500005;
int ls[maxn],rs[maxn],tot,rt;
double maxr[maxn],minr[maxn];
bool lazb[maxn];
struct node {
double a,b,c,d;
}ttmp,lazy[maxn];
inline void gaoji(int &p) {
if(maxr[p]<minr[p]) swap(maxr[p],minr[p]);
}
char buf[1<<20],*p1,*p2;
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
inline int R()
{
char t=GC;
int x=0;
while(!isdigit(t)) t=GC;
while(isdigit(t)) x=x*10+t-48,t=GC;
return x;
}
void bianhuan(node &x,node &aa,node &bb) {
ttmp.a = aa.a*bb.a + aa.c*bb.b;
ttmp.b = aa.b*bb.a + aa.d*bb.b;
ttmp.c = aa.a*bb.c + aa.c*bb.d;
ttmp.d = aa.b*bb.c + aa.d*bb.d;
ttmp.b /= ttmp.a;
ttmp.c /= ttmp.a;
ttmp.d /= ttmp.a;
ttmp.a = 1.0;
x = ttmp;
}
int n;
void chuanlian(node &x,int rr) {
x.a=1; x.b=1.0*rr; x.c=0; x.d=1.0;
}
void binglian(node &x,int rr) {
x.a=1.0*rr; x.b=0; x.c=1; x.d=1.0*rr;
}
double dairu(double x,node &hs) {
return ( ( hs.a * x + hs.b) / (hs.c * x + hs.d) );
}
void putdowm(int x) {
if(!lazb[x]||(!ls[x])) return;
maxr[ls[x]] = dairu(maxr[ls[x]],lazy[x]);
minr[ls[x]] = dairu(minr[ls[x]],lazy[x]);
gaoji(ls[x]);
if(!lazb[ls[x]]) lazb[ls[x]]=1,lazy[ls[x]]=lazy[x];
else bianhuan(lazy[ls[x]],lazy[ls[x]],lazy[x]);
maxr[rs[x]] = dairu(maxr[rs[x]],lazy[x]);
minr[rs[x]] = dairu(minr[rs[x]],lazy[x]);
gaoji(rs[x]);
if(!lazb[rs[x]]) lazb[rs[x]]=1,lazy[rs[x]]=lazy[x];
else bianhuan(lazy[rs[x]],lazy[rs[x]],lazy[x]);
lazb[x] = 0;
}
inline void update(int p) {
maxr[p] = max(maxr[ls[p]],maxr[rs[p]]);
minr[p] = min(minr[ls[p]],minr[rs[p]]);
}
void maketree(int &p,int l,int r) {
p = ++tot;
if(l==r) {
int x; x=R();
minr[p] = maxr[p] = (double)x; return;
}
int mid = (l+r)>>1;
maketree(ls[p],l,mid);
maketree(rs[p],mid+1,r);
update(p);
}
double querymax(int p,int l,int r,int x,int y) {
if(x<=l&&r<=y) return maxr[p];
putdowm(p);
int mid = (l+r)>>1;
if(y<=mid) return querymax(ls[p],l,mid,x,y);
else if(x>mid) return querymax(rs[p],mid+1,r,x,y);
else return max(querymax(ls[p],l,mid,x,y),querymax(rs[p],mid+1,r,x,y));
}
double querymin(int p,int l,int r,int x,int y) {
if(x<=l&&r<=y) return minr[p];
putdowm(p);
int mid = (l+r)>>1;
if(y<=mid) return querymin(ls[p],l,mid,x,y);
else if(x>mid) return querymin(rs[p],mid+1,r,x,y);
else return min(querymin(ls[p],l,mid,x,y),querymin(rs[p],mid+1,r,x,y));
}
void add(int p,int l,int r,int x,int y,node &d) {
if(x<=l&&r<=y) {
maxr[p] = dairu(maxr[p],d); minr[p] = dairu(minr[p],d);
if(!lazb[p]) { lazy[p] = d;lazb[p]=1; }
else bianhuan(lazy[p],lazy[p],d);
gaoji(p);
; return;
}
int mid = (l+r)>>1;
putdowm(p);
if(y<=mid) add(ls[p],l,mid,x,y,d);
else if(x>mid) add(rs[p],mid+1,r,x,y,d);
else add(ls[p],l,mid,x,y,d),add(rs[p],mid+1,r,x,y,d);
update(p);
}
int main() {
n=R();
maketree(rt,1,n);
int m; m=R();
for(int i=1;i<=m;i++) {
int opt,l,r,orz; opt=R();l=R();r=R();
switch(opt) {
case 1:{
printf("%.14lf\n",querymax(rt,1,n,l,r));
break;
}
case 2:{
printf("%.14lf\n",querymin(rt,1,n,l,r));
break;
}
case 3:{
orz=R();
node tmp; chuanlian(tmp,orz);
add(1,1,n,l,r,tmp);
break;
}
case 4:{
orz=R();
node tmp; binglian(tmp,orz);
add(1,1,n,l,r,tmp);
break;
}
}
}
}

浙公网安备 33010602011771号