先考虑暴力做法.对于每条路径,显然可以拆到路径上的每条边上,然后记录一下这个路径经过这条边的起始时间\(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; }
来源:https://www.cnblogs.com/smyjr/p/12401385.html