物理太差被虐了/(ㄒoㄒ)/~~
首先将电阻看成1欧不影响答案吧。。
考虑将一个点x的电势Ux,它父亲y的电势Uy,考虑将Ux用aUy+b的形式来表示,这样就可以利用树高为50的条件O(H)查询修改了。
对于任意一对点(x,y),考虑y->x的电流为(Uy-Ux+E)/R,忽略单位的话在数值上可以看成Uy-Ux+E。其中E为y->x的路上的电源带来的电势。那么根据基尔霍夫定律显然有ΣUy-Ux+E=0。而对于x的某一个儿子y,显然一直Uy=aUx+b,那么借助这个式子我们就可以推出x相对于x的父亲的a,b。注意到修改x只会影响x到根的a,b,因此记录一下某个点x到儿子的E的和就可以O(H)修改了。
另外发现,修改操作实际上是对某一条边x->y上面的E的修改,对任一点的a是没有影响的;因此预处理a然后修改b即可。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 50005
using namespace std;
int n,m,tot,fst[N],pnt[N<<1],nxt[N<<1],dgr[N],u[N],v[N],fa[N],q[N];
double a[N],b[N],s[N];
int read(){
int x=0; char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
return x;
}
void add(int x,int y){
dgr[y]++; pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;
}
void dfs(int x){
int p; a[x]=dgr[x];
for (p=fst[x]; p; p=nxt[p]){
int y=pnt[p];
if (y!=fa[x]){
fa[y]=x; dfs(y);
a[x]-=a[y];
}
}
a[x]=1/a[x];
}
void ins(int x,int z){
int y=fa[x]; u[x]+=z; v[y]+=z;
for (; x<n; x=y,y=fa[y]){
s[y]-=b[x];
b[x]=(s[x]+v[x]-u[x])*a[x];
s[y]+=b[x];
}
}
void qry(int x){
int tp=0,i; double ans=0;
for (; x<n; x=fa[x]) q[++tp]=x;
for (i=tp; i; i--) ans=ans*a[q[i]]+b[q[i]];
printf("%.12f\n",ans);
}
int main(){
n=read(); m=read(); int i,x,y,z;
for (i=1; i<n; i++){
x=read(); y=read();
add(x,y); add(y,x);
}
for (i=1; i<=n; i++)
if (dgr[i]==1) break;
add(i,++n); add(n,i);
for (i=1; i<n; i++) if (dgr[i]==1) dgr[i]++;
dfs(n);
char ch;
while (m--){
ch=getchar(); while (ch<'A' || ch>'Z') ch=getchar();
if (ch=='C'){
x=read(); y=read(); z=read();
if (x==fa[y]){
swap(x,y); z=-z;
}
ins(x,z);
} else qry(read());
}
return 0;
}
by lych
2016.5.23