Codeforces

这题……真是搞死我了……

好不容易下定了决心要不颓废,要写题,结果一调就调了十几个小时……

思路

我们发现在树上做非常不舒服,于是树链剖分之后一次在重链上的移动就可以看做是在dfs序上移动,也就是在序列上走。

于是把时间作为\(x\)轴,dfs序作为\(y\)轴,那么一次移动就可以看做一条线段。

我们就要找所有线段里面最早相交的交点。

这是一个经典问题。我们在\(x\)坐标上面扫描线,用set维护线段,加入线段的时候求一下和前驱后继的交点,删除的时候求一下前驱后继的交点,一旦当前时间超出了答案那么立刻退出,正确性就没有问题。

有一些细节,比如重链头上面那条边也要算到这条重链上,而且不同重链最好分开计算。还有加入线段的时候如果有线段刚好过起始点那么set会判成这两个线段相等,就会插入失败,所以可能还要特判。

也不怎么卡精度,但我就是调了一下午+一晚上才过……也许这就是菜吧/kk

代码

#include<bits/stdc++.h>
clock_t t=clock();
namespace my_std{
using namespace std;
#define pii pair<int,int>
#define fir first
#define sec second
#define MP make_pair
#define rep(i,x,y) for (int i=(x);i<=(y);i++)
#define drep(i,x,y) for (int i=(x);i>=(y);i--)
#define go(x) for (int i=head[x];i;i=edge[i].nxt)
#define templ template<typename T>
#define sz 101010
typedef long long ll;
typedef long double db;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
templ inline T rnd(T l,T r) {return uniform_int_distribution<T>(l,r)(rng);}
templ inline bool chkmax(T &x,T y){return x<y?x=y,1:0;}
templ inline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templ inline void read(T& t)
{
t=0;char f=0,ch=getchar();double d=0.1;
while(ch>'9'||ch<'0') f|=(ch=='-'),ch=getchar();
while(ch<='9'&&ch>='0') t=t*10+ch-48,ch=getchar();
if(ch=='.'){ch=getchar();while(ch<='9'&&ch>='0') t+=d*(ch^48),d*=0.1,ch=getchar();}
t=(f?-t:t);
}
template<typename T,typename... Args>inline void read(T& t,Args&... args){read(t); read(args...);}
char __sr[1<<21],__z[20];int __C=-1,__zz=0;
inline void Ot(){fwrite(__sr,1,__C+1,stdout),__C=-1;}
inline void print(register int x)
{
if(__C>1<<20)Ot();if(x<0)__sr[++__C]='-',x=-x;
while(__z[++__zz]=x%10+48,x/=10);
while(__sr[++__C]=__z[__zz],--__zz);__sr[++__C]='\n';
}
void file()
{
#ifdef NTFOrz
freopen("a.in","r",stdin);
#endif
}
inline void chktime()
{
#ifndef ONLINE_JUDGE
cout<<(clock()-t)/1000.0<<'\n';
#endif
}
#ifdef mod
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x%mod) if (y&1) ret=ret*x%mod;return ret;}
ll inv(ll x){return ksm(x,mod-2);}
#else
ll ksm(ll x,int y){ll ret=1;for (;y;y>>=1,x=x*x) if (y&1) ret=ret*x;return ret;}
#endif
// inline ll mul(ll a,ll b){ll d=(ll)(a*(double)b/mod+0.5);ll ret=a*b-d*mod;if (ret<0) ret+=mod;return ret;}
}
using namespace my_std; const db eps=1e-9; int n,m;
struct hh{int t,nxt;}edge[sz<<1];
int head[sz],ecnt;
void make_edge(int f,int t)
{
edge[++ecnt]=(hh){t,head[f]};
head[f]=ecnt;
edge[++ecnt]=(hh){f,head[t]};
head[t]=ecnt;
} int dfn[sz],top[sz],son[sz],size[sz],fa[sz],dep[sz],cnt;
#define v edge[i].t
void dfs1(int x,int fa)
{
dep[x]=dep[::fa[x]=fa]+1;size[x]=1;
go(x) if (v!=fa)
{
dfs1(v,x);
size[x]+=size[v];
if (size[v]>size[son[x]]) son[x]=v;
}
}
void dfs2(int x,int fa,int tp)
{
dfn[x]=++cnt;top[x]=tp;
if (son[x]) dfs2(son[x],x,tp);
go(x) if (v!=fa&&v!=son[x]) dfs2(v,x,v);
}
#undef v #define I inline
I int dcmp(db x){return fabs(x)<=eps?0:(x>0?1:-1);}
struct Vector
{
db x,y;
Vector(db xx=0,db yy=0){x=xx,y=yy;}
I const Vector operator + (const Vector &a) const {return Vector(x+a.x,y+a.y);}
I const Vector operator - (const Vector &a) const {return Vector(x-a.x,y-a.y);}
I const Vector operator * (const db &a) const {return Vector(x*a,y*a);}
I const Vector operator / (const db &a) const {return Vector(x/a,y/a);}
I const bool operator < (const Vector &a) const {return dcmp(x-a.x)==0?dcmp(y-a.y)<0:dcmp(x-a.x)<0;}
I const bool operator == (const Vector &a) const {return dcmp(x-a.x)==0&&dcmp(y-a.y)==0;}
I const bool operator != (const Vector &a) const {return dcmp(x-a.x)!=0||dcmp(y-a.y)!=0;}
};
typedef Vector Point;
I db Dot(Vector a,Vector b){return a.x*b.x+a.y*b.y;}
I db Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
I db Len(Vector a){return sqrt(Dot(a,a));}
struct Line
{
Point a,b;
Line(){}
Line(Point aa,Point bb){a=aa,b=bb;}
};
vector<Line>vec[sz];
struct hhh
{
db x;int id,type;
const bool operator < (const hhh &a) const
{
if (dcmp(x-a.x)) return x<a.x;
return type<a.type;
}
}ss[sz*20];
typedef Line seg;
I bool OnSeg(Point p,seg x){Point a=x.a,b=x.b;return dcmp(Cross(p-a,a-b))==0&&dcmp(Dot(p-a,p-b))<=0;}
I Point LI(Line l1,Line l2)
{
Vector v=l1.a-l2.a,v1=l1.b-l1.a,v2=l2.b-l2.a;
db t=Cross(v,v2)/Cross(v2,v1);
return l1.a+v1*t;
}
I bool LSI(Line l,Point a,Point b)
{
Vector v=l.b-l.a,v1=a-l.a,v2=b-l.a;
return dcmp(Cross(v,v1))!=dcmp(Cross(v,v2));
}
I db SSI(seg l1,seg l2)
{
db ret=1e9;
if (OnSeg(l1.a,l2)) chkmin(ret,l1.a.x);
if (OnSeg(l1.b,l2)) chkmin(ret,l1.b.x);
if (OnSeg(l2.a,l1)) chkmin(ret,l2.a.x);
if (OnSeg(l2.b,l1)) chkmin(ret,l2.b.x);
if (ret<1e9) return ret;
if (!LSI(l1,l2.a,l2.b)||!LSI(l2,l1.a,l1.b)) return 1e9;
return LI(l1,l2).x;
} int lca(int x,int y)
{
while (top[x]!=top[y])
{
if (dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]>dep[y]?y:x;
}
void add(int x,int y,db T,db V)
{
V=1.0/V;
int l=lca(x,y);db Len=dep[y]-dep[l];
while (top[x]!=top[l])
{
db len=dep[x]-dep[top[x]]+1;
vec[top[x]].push_back(seg(Point(T,dfn[x]),Point(T+len*V,dfn[top[x]]-1)));
x=fa[top[x]];T+=len*V;
}
db len=dep[x]-dep[l];
if (x!=l) vec[top[x]].push_back(seg(Point(T,dfn[x]),Point(T+len*V,dfn[l])));T+=len*V;
while (top[y]!=top[l])
{
db len=dep[y]-dep[top[y]]+1;Len-=len;
vec[top[y]].push_back(seg(Point(T+Len*V,dfn[top[y]]-1),Point(T+len*V+Len*V,dfn[y])));
y=fa[top[y]];
}
len=dep[y]-dep[l];
if (y!=l) vec[top[y]].push_back(seg(Point(T,dfn[l]),Point(T+len*V,dfn[y])));
if (x==l&&y==l) vec[top[l]].push_back(seg(Point(T,dfn[l]),Point(T,dfn[l])));
} vector<seg>s;
db T;
struct cmp
{
const bool operator () (const int &x,const int &y) const
{
seg l1=s[x],l2=s[y];
db y1;
if (dcmp(l1.b.x-l1.a.x)) y1=(l1.a+(l1.b-l1.a)*(T-l1.a.x)/(l1.b.x-l1.a.x)).y;
else y1=l1.a.y;
db y2;
if (dcmp(l2.b.x-l2.a.x)) y2=(l2.a+(l2.b-l2.a)*(T-l2.a.x)/(l2.b.x-l2.a.x)).y;
else y2=l2.a.y;
return y1<y2;
}
};
set<int,cmp>S;
db ans=1e9;
void work()
{
db ans=1e9;
int M=s.size();s.push_back(seg(Point(),Point()));
rep(i,0,M-1) ss[i*2]=(hhh){s[i].a.x,i,0},ss[i*2+1]=(hhh){s[i].b.x,i,1};
sort(ss,ss+M+M);
rep(i,0,M+M-1)
{
if (ss[i].x>ans) break;
if (ss[i].type)
{
auto it=S.find(ss[i].id);
if (it!=S.begin()&&next(it)!=S.end()) chkmin(ans,SSI(s[*prev(it)],s[*next(it)]));
S.erase(ss[i].id);
}
else
{
T=ss[i].x;
s[M]=seg(Point(T,s[ss[i].id].a.y),Point(T,s[ss[i].id].a.y));
if (S.find(M)!=S.end()) {ans=T;break;}
auto it=S.insert(ss[i].id).fir;
if (it!=S.begin()) chkmin(ans,SSI(s[*it],s[*prev(it)]));
if (next(it)!=S.end()) chkmin(ans,SSI(s[*it],s[*next(it)]));
}
}
chkmin(::ans,ans);
S.clear();
} int main()
{
file();
read(n,m);
int x,y;
rep(i,1,n-1) read(x,y),make_edge(x,y);
dfs1(1,0),dfs2(1,0,1);
while (m--)
{
int v,t;read(t,v,x,y);
add(x,y,t,v);
}
rep(i,1,n) if (top[i]==i) s=vec[i],work();
if (ans<1e9) cout<<setprecision(20)<<fixed<<ans;
else puts("-1");
return 0;
}

Codeforces 704E Iron Man [树链剖分,计算几何]的更多相关文章

  1. CodeForces 343D water tree(树链剖分)

    Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a res ...

  2. Educational Codeforces Round 3 E. Minimum spanning tree for each edge (最小生成树+树链剖分)

    题目链接:http://codeforces.com/contest/609/problem/E 给你n个点,m条边. 问枚举每条边,问你加这条边的前提下组成生成树的权值最小的树的权值和是多少. 先求 ...

  3. Codeforces Round #329 (Div. 2) D. Happy Tree Party 树链剖分

    D. Happy Tree Party Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/593/p ...

  4. 【Codeforces】【网络流】【树链剖分】【线段树】ALT (CodeForces - 786E)

    题意 现在有m个人,每一个人都特别喜欢狗.另外还有一棵n个节点的树. 现在每个人都想要从树上的某个节点走到另外一个节点,且满足要么这个人自带一条狗m,要么他经过的所有边h上都有一条狗. 2<=n ...

  5. Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组

    Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations ...

  6. D. Happy Tree Party CodeForces 593D【树链剖分,树边权转点权】

    Codeforces Round #329 (Div. 2) D. Happy Tree Party time limit per test 3 seconds memory limit per te ...

  7. Water Tree CodeForces 343D 树链剖分+线段树

    Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...

  8. CodeForces - 343D 树链剖分

    题目链接:http://codeforces.com/problemset/problem/343/D 题意:给定一棵n个n-1条边的树,起初所有节点权值为0,然后m个操作. 1 x:把x为根的子树的 ...

  9. Codeforces 856D - Masha and Cactus(树链剖分优化 dp)

    题面传送门 题意: 给你一棵 \(n\) 个顶点的树和 \(m\) 条带权值的附加边 你要选择一些附加边加入原树中使其成为一个仙人掌(每个点最多属于 \(1\) 个简单环) 求你选择的附加边权值之和的 ...

随机推荐

  1. springboot_4 spring boot 使用servlet,filter,listener和interceptor

    上一篇我们学习了 spring boot 利用Controller响应数据与响应页面. 一般的Web开发使用 Controller 基本上可以完成大部分需求,但是有的时候我们还是会用到 Servlet ...

  2. js时间格式化和相互转换

    1. Thu Mar 07 2019 12:00:00 GMT+0800 (中国标准时间) 转换为 2019-03-07 12:00:00 const d = new Date(Thu Mar 07 ...

  3. js控制台不同的打印方式

    在控制台单个输出: console.log(...):值 console.info(...):信息 console.debug(...):调试信息 console.warn(...):警告信息 con ...

  4. 【charlse】charlse功能

    (一)主界面介绍 一.工具导航栏 Charles 顶部为菜单导航栏,菜单导航栏下面为工具导航栏.视图如下图所示: 工具导航栏中提供了几种常用工具:  :清除捕获到的所有请求  :红点状态说明正在捕获请 ...

  5. 【leetcode】544. Output Contest Matches

    原题 During the NBA playoffs, we always arrange the rather strong team to play with the rather weak te ...

  6. Windows 如何录屏

    从Windows10开始,Windows开始自带了录屏功能(XBOX附带的).本来是方便游戏录制,但日常的录制也不在话下. 快捷键:Win + G 打开XBOX的录制工具 在打开录制工具后 Win + ...

  7. 搭建jumpser堡垒机

    安装环境centos7 生产环境建议使用 1.4.8 版本 1.开始安装 echo -e "\033[31m 1. 防火墙 Selinux 设置 \033[0m" \ && ...

  8. 使用Ponysay,在Linux终端显示彩虹小马

    Ponysay类似于Cowsay,可以在终端打印所有小马的像素画.还有个ponythink,这个是小马想,那个是小马说,效果如下: 安装: sudo apt-get install ponysay 使 ...

  9. WebApi增加Oauth2认证

    前期搭建可看这篇博文:https://www.cnblogs.com/lnice/p/6857203.html,此博文是在本篇博文实践才产生的,在实践中,也产生了几个问题,希望能够共同交流,一起进步. ...

  10. 安装腾讯QQ问题记录

    安装腾讯QQ的时候遇到两个错误,记录一些解决方法 1.安装文件失败,请尝试手动卸载QQ或更改安装目录,再执行安装程序,错误码:0x00008013 问题原因:卸载QQ没有完全卸载,导致文件残留. 如果 ...