先考慮暴力做法.對於每條路徑,顯然可以拆到路徑上的每條邊上,然後記錄一下這個路徑經過這條邊的起始時間\(xl\)和終止時間\(xr\).然後在平面直角座標系上,上行的邊對應連接\((xl,0),(xr,1)\),下行的邊對應連接\((xl,1),(xr,0)\),那麼這條邊的貢獻就是所有線段交點的橫座標最小值
因爲給出的是一段路徑,我們可以聯想到樹剖,把一條路徑拆在\(log\)條重鏈上,然後對於每條重鏈統計答案.對於一條路徑,設它經過這個重鏈的起始時間\(xl\)對應所在深度爲\(yl\),終止時間\(xr\)對應所在深度爲\(yr\),那麼在平面上連接\((xl,yl),(xr,yr)\).現在問題變成求一個線段集合的交點橫座標最小值.這裏對橫座標做掃描線,每條線段對應會在起始橫座標被加入,在終止橫座標被刪除.我們維護代表所有經過當前掃描線的multiset,按照線段在當前\(x\)的縱座標爲關鍵字排序.由於一條線段最早只會和上下兩條線段相交,所以加入一條線段時就用當前線段和前驅線段的交點橫座標和當前線段和後繼線段的交點橫座標更新答案;當刪除一個線段時,這個線段的前驅和後繼會相鄰,那麼用前驅和後繼的交點更新答案
以及你可能要注意yi些細節,例如重鏈頂端到父親的那條邊也要算進重鏈;求兩個線段交點要考慮線段重合問題(換句話說是在當前掃描線的縱座標一樣);如果當前掃描線橫座標不小於答案的就直接退出,一來是提高程序運行效率,二來是因爲multiset的關鍵字是一個關於\(x\)的一次函數,所以如果出現交點的繼續做就會出現set裏兩個元素相對大小出問題的情況
#include<bits/stdc++.h>
#define LL long long
#define db double
using namespace std;
const int N=1e5+10;
const db eps=1e-10;
int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
void adde(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int n,m,fa[N],de[N],sz[N],hs[N],dfn[N],ti,top[N];
void dfs1(int x)
{
sz[x]=1;
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==fa[x]) continue;
fa[y]=x,de[y]=de[x]+1,dfs1(y);
sz[x]+=sz[y],hs[x]=sz[hs[x]]>sz[y]?hs[x]:y;
}
}
void dfs2(int x)
{
dfn[x]=++ti;
if(hs[x]) top[hs[x]]=top[x],dfs2(hs[x]);
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==fa[x]||y==hs[x]) continue;
top[y]=y,dfs2(y);
}
}
int glca(int x,int y)
{
while(top[x]!=top[y])
{
if(de[top[x]]<de[top[y]]) swap(x,y);
x=fa[top[x]];//x=top[x]=>TLE on test 37
}
return de[x]<de[y]?x:y;
}
int tz;
db ps[N*30][2],pt,ans=114514;
struct node
{
db x,k,b;
int i,o;
bool operator < (const node &bb) const
{
db s1=k*pt+b,s2=bb.k*pt+bb.b;
if(fabs(s1-s2)>eps) return s1<s2;
if(fabs(x-bb.x)>eps) return x<bb.x;
if(o!=bb.o) return o<bb.o;
return i<bb.i;
}
db s(db x){return k*x+b;}
}bz[N*30];
bool cmp(node aa,node bb){return fabs(aa.x-bb.x)>eps?aa.x<bb.x:aa.o>bb.o;}
vector<node> qr[N];
void addq(int x,db xl,db xr,db yl,db yr)
{
ps[++tz][0]=xl,ps[tz][1]=xr;
db nk=fabs(xl-xr)>eps?(yr-yl)/(xr-xl):1,nb=yl-nk*xl;
qr[top[x]].push_back((node){xl,nk,nb,tz,1});
qr[top[x]].push_back((node){xr,nk,nb,tz,0});
}
multiset<node> sb;
multiset<node>::iterator it,ft,nx;
void cal(int i,int j)
{
if(max(ps[i][0],ps[j][0])>min(ps[i][1],ps[j][1])+eps) return;
if(fabs(bz[i].k-bz[j].k)<eps)
{
if(fabs(bz[i].b-bz[j].b)>eps) return;
ans=min(ans,max(ps[i][0],ps[j][0]));
return;
}
if(fabs(bz[j].s(pt)-bz[i].s(pt))<eps){ans=min(ans,pt);return;}
db nv=bz[i].k<bz[j].k?-1:pt+(bz[j].s(pt)-bz[i].s(pt))/(bz[i].k-bz[j].k);
if(nv>max(ps[i][0],ps[j][0])-eps&&nv<min(ps[i][1],ps[j][1])+eps)
ans=min(ans,nv);
}
int main()
{
//////
n=rd(),m=rd();
for(int i=1;i<n;++i) adde(rd(),rd());
de[1]=1,dfs1(1);
top[1]=1,dfs2(1);
while(m--)
{
db t=rd(),v=rd();
v=1/v;
int x=rd(),y=rd(),lca=glca(x,y);
bool fg=0;
db xl,xr,yl,yr,lt=t+v*(db)(de[x]+de[y]-2*de[lca]);
while(top[x]!=top[lca])
{
xl=t,xr=t+v*(db)(de[x]-de[fa[top[x]]]),yl=dfn[x],yr=(db)dfn[top[x]]-1;
addq(x,xl,xr,yl,yr);
t=xr,x=fa[top[x]];
}
if(de[lca]<de[x])
{
xl=t,xr=t+v*(db)(de[x]-de[lca]),yl=dfn[x],yr=dfn[lca];
fg=1,addq(lca,xl,xr,yl,yr);
}
t=lt;
while(top[y]!=top[lca])
{
xl=t-v*(db)(de[y]-de[fa[top[y]]]),xr=t,yl=(db)dfn[top[y]]-1,yr=dfn[y];
addq(y,xl,xr,yl,yr);
t=xl,y=fa[top[y]];
}
if(de[lca]<de[y])
{
xl=t-v*(db)(de[y]-de[lca]),xr=t,yl=dfn[lca],yr=dfn[y];
fg=1,addq(lca,xl,xr,yl,yr);
}
if(!fg) addq(top[lca],t,t,dfn[lca],dfn[lca]);
}
for(int x=1;x<=n;++x)
{
int tq=qr[x].size();
if(!tq) continue;
sort(qr[x].begin(),qr[x].end(),cmp);
sb.clear();
for(int i=0;i<tq;++i)
{
pt=qr[x][i].x;
if(pt>ans-eps) break;
int j=qr[x][i].i,k=0,l=0;
if(qr[x][i].o)
{
bz[j]=(node){pt,qr[x][i].k,qr[x][i].b,j,1};
it=sb.insert(bz[j]);
if(it!=sb.begin())
ft=it,k=(*(--ft)).i,cal(k,j);
if(it!=(--sb.end()))
nx=it,l=(*(++nx)).i,cal(j,l);
}
else
{
it=sb.find(bz[j]);
assert((*it).i==j);
if(it!=sb.begin()) ft=it,k=(*(--ft)).i;
if(it!=(--sb.end())) nx=it,l=(*(++nx)).i;
if(k&&l) cal(k,l);
sb.erase(it);
}
}
}
ans<114514?printf("%.8lf\n",ans):puts("-1");
return 0;
}