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. Linux踢出登陆用户的正确姿势

    首先who(或w)查看需要杀死的终端名,然后执行: pkill -9 -t pts/? pkill相当于ps和kill的结合,用法和killall类似,根据进程名来杀死一类进程(kill是杀死单个) ...

  2. hdu 2539 虽然是水题 wa了很多次 说明自己的基本功不扎实 需要打好基础先 少年

    两点吧 1.gets使用的时候 确保上一次的回车符对其没有影响 getline也是如此 这样的细节..  多注意啊!! 2.编写程序的时候 对一些极端的情况要多调试 比如此题当 n==1的时候..  ...

  3. C#-Json-抽象类的反序列化

    引用: using System; using System.Collections.Generic; using Newtonsoft.Json; using Newtonsoft.Json.Lin ...

  4. html中标签的英文含义!

    html中的标签缩写的英文是什么?  标签  英文全称  含义 ul unordered lists 无序列表 li list item 列表项目 ol ordered lists 有序列表 dl d ...

  5. java.sql.Date和java.sql.Timestamp转换

    转自:https://www.xuebuyuan.com/1479399.html 在开发web应用中,针对不同的数据库日期类型,我们需要在我们的程序中对日期类型做各种不同的转换.若对应数据库数据是o ...

  6. [#Linux] CentOS 7 应用程序添加快捷方式到桌面

    在centos使用中,会发现应用程序只能到eclipse的目录中执行eclipse的脚本去启动.这样很不方便. 查阅资料后找到了解决方案: 1.通过命令行,进入到桌面文件夹中 cd /home/you ...

  7. [#Linux] CentOS 7 配置JDK后,eclipse无法启动,提示jdk路径错误。

    ​​​​ 解决方案:在eclipse的目录下创建一个jre文件夹,在jre文件夹里创建一个jdk的bin目录的链接 1.进入到eclipse目录下,右键在终端打开. 2.创建jre目录:mkdir j ...

  8. iveiw DatePicker 只能选择本月之前的日期,本月包括之后都不能选择

    日期判断只能选择本月之前的日期 <DatePicker type="date" :options="options3" format="yyyy ...

  9. 算法学习:我终于明白二分查找的时间复杂度为什么是O(logn)了

    最近发现了个好东西,就是一个学算法的好东西,是网易公开课的一个视频. 直通车 这是麻省理工学院的公开课,有中英字幕,感谢网易.. 也可以在App把视频缓存下来之后再放到电脑上面看,因为我这样可以倍速, ...

  10. AD19新功能之交互式等长

    多信号线等长 选中需要等长的信号线: 选择“Interaction Length Tuning”命令,然后在网络线上点击一下,然后 tab 键暂停: 在Properties面板中,修改Source部分 ...