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. 应用编排服务之ELK技术栈示例模板详解

    日志对互联网应用的运维尤为重要,它可以帮助我们了解服务的运行状态.了解数据流量来源甚至可以帮助我们分析用户的行为等.当进行故障排查时,我们希望能够快速的进行日志查询和过滤,以便精准的定位并解决问题. ...

  2. 立体像对空间前方交会-点投影系数法(python实现)

    一.原理 二.步骤 a.用各自像片的角元素计算出左右像片的旋转矩阵R1和R2. b.根据左右像片的外方位元素计算摄影基线分量Bx,By,Bz. c.逐点计算像点的空间辅助坐标. d.计算投影系数. e ...

  3. YIii2.0-学习笔记之服务器安装

    最近项目需要,学习了一下yii2.0框架 第一步:  安装composer--------作为一个phper  composer不会用可能有点不合适 下载composer.phar文件 #curl - ...

  4. SpringCloud使用Consul作为分布式配置中心

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_36027670/article/de ...

  5. Tomcat一闪而过的调试方法

    很少用tomcat来部署,都是用springboot微服务.只是以前学的时候搞demo试过而已. 软件测试的期末作业要求要测一个Javaweb的项目,给了一个包然后要求部署在tomcat中并启动. 然 ...

  6. 解决 VUE项目过大nodejs内存溢出问题

    今天在启动vue项目的时候报了这样一个错误, 如图所示:频繁出现此种情况,项目太大,导致内存溢出,排除代码问题外,可参照以下方式解决 // 全局安装increase-memory-limit npm ...

  7. java线程中如何使用spring依赖注入

    实现一个线程继承了Thread或实现Runnable接口,想在run方法中使用spring依赖注入(操作数据库),此时报错为空指针,就是说没有注入进来. 实验了几种方式,分别说一下优缺点. 1:写了工 ...

  8. npoi 实现类似excel、word自身的加密解密效果

    最近在做一个文件管理系统,要求上传的excel.word.pdf 文件加密存在服务器上.在系统里下载可以不输密码直接打开,在服务器上点开文件必须要输密码.要考虑做好一劳永逸.也不能用收费的.以前没做过 ...

  9. Powershell-获取Hyper-V复制状态

    Get-VM | Select-Object name,ReplicationHealth

  10. cmd中for的用法

    在cmd窗口输入for /?后的原文,被我自己“翻译”了一下,更像人话了. 推荐去https://www.cnblogs.com/cbugs/p/8992059.html这篇部落格里去看看,讲的更好. ...