此题就是在基环树上的询问
答案分为两部分,一部分是以询问限速开过的时间,一部分是以当前路的限速开过的段。
考虑离线,每次讲限速小于当前询问的限速的路段权值修改。
S->T如果在去环后在同一棵树上,就直接树链+树状数组。
如果不在同一棵树上就取他们到根路径的权值和和环上两种走法的较小值作为答案。
环上边另开树状数组即可
(claris只去一条边变为一棵树的太神了)
#include <bits/stdc++.h>
#define gc getchar()
#define N 100009
using namespace std;
int n,m,qq,first[N],number=1,v[N],w[N],vis[N],pre[N],root[N],so[N],sw[N];
int root_num,rt[N],fa[N],size[N],Mson[N],deep[N],top[N],cnt,dfn[N],id[N];
int is_root[N],limit[4];
double Ans[N],bit[N<<1][4];
map<int,int> mp;
struct edge
{
int to,next,len,pd,pos,lev;
double val,v;
void add(int x,int y,int z,int l,int p)
{
to=y,next=first[x],first[x]=number,lev=z,len=l,pos=p;
}
}e[N<<1];
struct Qry
{
int x,y,pos;
double v;
bool operator <(const Qry &rhs) const
{
return v<rhs.v;
}
}q[N];
bool cmp(const int &x,const int &y)
{
return e[x].v<e[y].v;
}
int read()
{
int x=1;
char ch;
while (ch=gc,ch<'0'||ch>'9') if (ch=='-') x=-1;
int s=ch-'0';
while (ch=gc,ch<='9'&&ch>='0') s=s*10+ch-'0';
return s*x;
}
int lowbit(int x)
{
return x&(-x);
}
void add(int x,double y,int k)
{
for (;x<=limit[k];x+=lowbit(x)) bit[x][k]+=y;
}
double qry(int x,int k=0,double ret=0.0)
{
for (;x;x-=lowbit(x)) ret+=bit[x][k];
return ret;
}
double qry(int x,int y,int k)
{
return qry(y,k)-qry(x-1,k);
}
void dfs(int x,int last)
{
vis[x]=1;
for (int i=first[x];i;i=e[i].next)
if (vis[e[i].to]&&i!=(last^1))
{
int now=x;
while (now!=e[i].to)
{
e[pre[now]].pd=e[pre[now]^1].pd=1;
mp[pre[now]]=mp[pre[now]^1]=now;
root[++root_num]=now;
now=e[pre[now]^1].to;
}
e[i].pd=e[i^1].pd=1;
mp[i]=mp[i^1]=e[i].to;
root[++root_num]=e[i].to;
pre[e[i].to]=i;
break;
}
else
if (!vis[e[i].to]&&i!=(last^1))
{
pre[e[i].to]=i;
dfs(e[i].to,i);
if (root_num) break;
}
}
void dfs1(int x,int r)
{
rt[x]=r;
size[x]=1;
deep[x]=deep[fa[x]]+1;
for (int i=first[x];i;i=e[i].next)
if (!e[i].pd&&e[i].to!=fa[x])
{
pre[e[i].to]=i;
mp[i]=mp[i^1]=e[i].to;
fa[e[i].to]=x;
dfs1(e[i].to,r);
size[x]+=size[e[i].to];
if (size[e[i].to]>size[Mson[x]]) Mson[x]=e[i].to;
}
}
void dfs2(int x,int y)
{
id[dfn[x]=++cnt]=x;
top[x]=y;
if (Mson[x]) dfs2(Mson[x],y);
for (int i=first[x];i;i=e[i].next)
if (e[i].to!=fa[x]&&e[i].to!=Mson[x]&&!e[i].pd) dfs2(e[i].to,e[i].to);
}
double query(int x,int y,double z,double ret=0.0)
{
for (;top[x]!=top[y];x=fa[top[x]])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
ret+=qry(dfn[top[x]],dfn[x],0)+qry(dfn[top[x]],dfn[x],1)/z;
}
if (deep[x]>deep[y]) swap(x,y);
ret+=qry(dfn[x]+1,dfn[y],0)+qry(dfn[x]+1,dfn[y],1)/z;
return ret;
}
int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
n=read(),m=read(),qq=read();
for (int i=1;i<=n;i++)
{
int x=read(),y=read(),l=read(),z=read();
e[++number].add(x,y,z,l,i);
e[++number].add(y,x,z,l,i);
}
for (int i=1;i<=m;i++) v[i]=read(),w[i]=read();
for (int i=1;i<=n;i++)
{
int level=e[i<<1].lev;
e[i<<1].v=e[i<<1|1].v=v[level];
e[i<<1].val=e[i<<1|1].val=(double)e[i<<1].len*w[level];
}
dfs(1,0);
for (int i=1;i<=root_num;i++)
sw[i]=root[root_num-i+1];
for (int i=1;i<=root_num;i++)
{
root[i]=sw[i];
dfs1(root[i],root[i]),dfs2(root[i],root[i]);
is_root[root[i]]=i;
}
for (int i=1;i<=n;i++) so[i]=i<<1;
sort(so+1,so+n+1,cmp);
for (int i=1;i<=qq;i++)
q[i].x=read(),q[i].y=read(),q[i].v=read(),q[i].pos=i;
limit[0]=limit[1]=n,limit[2]=limit[3]=(root_num<<1);
for (int i=1;i<=(root_num<<1);i++)
add(i,e[pre[root[(i-1)%root_num+1]]].val,3);
sort(q+1,q+qq+1);
for (int i=1;i<=n;i++)
if (!is_root[i]) add(dfn[i],e[pre[i]].val,1);
int now_edge=1;
for (int i=1;i<=qq;i++)
{
while (now_edge<=n&&e[so[now_edge]].v<=q[i].v)
{
int now=so[now_edge];
if (e[now].pd)
{
//cout<<"updata edge:"<<e[now].to<<" "<<e[now^1].to<<endl;
add(is_root[mp[now]],e[now].val/e[now].v,2);
add(is_root[mp[now]],-e[now].val,3);
add(is_root[mp[now]]+root_num,e[now].val/e[now].v,2);
add(is_root[mp[now]]+root_num,-e[now].val,3);
}
else
{
add(dfn[mp[now]],e[now].val/e[now].v,0);
add(dfn[mp[now]],-e[now].val,1);
}
now_edge++;
}
int r1=rt[q[i].x],r2=rt[q[i].y];
if (r1==r2) Ans[q[i].pos]=query(q[i].x,q[i].y,q[i].v);
else
{
Ans[q[i].pos]=query(q[i].x,r1,q[i].v)+query(q[i].y,r2,q[i].v);
int R1=is_root[r1],R2=is_root[r2];
if (R1>R2) swap(R1,R2);
double val1=qry(R1+1,R2,2)+qry(R1+1,R2,3)/q[i].v;
double val2=qry(R2+1,R1+root_num,2);
val2+=qry(R2+1,R1+root_num,3)/q[i].v;
Ans[q[i].pos]+=min(val1,val2);
}
}
for (int i=1;i<=qq;i++)
printf("%lf\n",Ans[i]);
return 0;
}