Codeforces 704E Iron Man [树链剖分,计算几何]
这题……真是搞死我了……
好不容易下定了决心要不颓废,要写题,结果一调就调了十几个小时……
思路
我们发现在树上做非常不舒服,于是树链剖分之后一次在重链上的移动就可以看做是在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 [树链剖分,计算几何]的更多相关文章
- CodeForces 343D water tree(树链剖分)
Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a res ...
- Educational Codeforces Round 3 E. Minimum spanning tree for each edge (最小生成树+树链剖分)
题目链接:http://codeforces.com/contest/609/problem/E 给你n个点,m条边. 问枚举每条边,问你加这条边的前提下组成生成树的权值最小的树的权值和是多少. 先求 ...
- 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 ...
- 【Codeforces】【网络流】【树链剖分】【线段树】ALT (CodeForces - 786E)
题意 现在有m个人,每一个人都特别喜欢狗.另外还有一棵n个节点的树. 现在每个人都想要从树上的某个节点走到另外一个节点,且满足要么这个人自带一条狗m,要么他经过的所有边h上都有一条狗. 2<=n ...
- 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 ...
- 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 ...
- Water Tree CodeForces 343D 树链剖分+线段树
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
- CodeForces - 343D 树链剖分
题目链接:http://codeforces.com/problemset/problem/343/D 题意:给定一棵n个n-1条边的树,起初所有节点权值为0,然后m个操作. 1 x:把x为根的子树的 ...
- Codeforces 856D - Masha and Cactus(树链剖分优化 dp)
题面传送门 题意: 给你一棵 \(n\) 个顶点的树和 \(m\) 条带权值的附加边 你要选择一些附加边加入原树中使其成为一个仙人掌(每个点最多属于 \(1\) 个简单环) 求你选择的附加边权值之和的 ...
随机推荐
- Linux下用命令来执行kettle文件资源库的文件ktr与kjb的方法
转载地址: https://blog.csdn.net/zuolovefu/article/details/78083445 1. 准备工作 一个简单的job,一个简单的trans. trans:读取 ...
- PHP Math常量
常量名 常量名 常量值 PHP M_E e 2.7182818284590452354 4 M_EULER Euler 常量 0.57721566490153286061 5.2.0 M_LNPI l ...
- 启动 docker 容器时报错
错误信息: iptables failed: iptables --wait -t nat -A DOCKER -p tcp -d 0/0 --dport 9300 -j DNAT --to-dest ...
- HTTP响应状态码整理
1xx:信息 100 Continue服务器仅接收到部分请求,但是一旦服务器并没有拒绝该请求,客户端应该继续发送其余的请求.101 Switching Protocols服务器转换协议:服务器将遵从客 ...
- WebClient 下载文件
WebClient用法小结(转载) 如果只想从特定的URI请求文件,则使用WebClient,它是最简单的.NET类,它只用一两条命令执行基本操作,.NET FRAMEWORK目前支持以http: ...
- 【转载】Windows检测到IP地址冲突
今天在使用电脑的过程中,突然弹出个提示,Windows检测到IP地址冲突,此网络中的另一台计算机与该计算机的IP地址相同.联系你的网络管理员解决此问题,有关详细信息,请参阅Windows系统日志.查阅 ...
- Python:GeoJson格式的多边形裁剪Tiff影像并计算栅格数值
JSON是通过键值对表示数据对象的一种格式,其全称为JavaScript Object Notation,它采用完全独立于编程语言的文本格式来存储和表示数据,轻量级.简洁清晰的层次结构.容易解析等特点 ...
- Windows Server 2012 R2上安装.Net4.6.1出错
在Windows Server 2012 R2上安装.Net4.6.1时提示“你需要先安装对应于 KB2919355 的更新,然后才可在……”解决方式: 在官网下载更新包,下载地址:https://w ...
- sql sever2008 R2 检测到索引可能已损坏。请运行 DBCC CHECKDB。
1.设置成单用户状态 USE MASTER ALTER DATABASE DBNAME SET SINGLE_USER; GO --DBNAME为修复的数据库名 2.执行修复语句,检查和修复数据库及索 ...
- iveiw DatePicker 只能选择本月之前的日期,本月包括之后都不能选择
日期判断只能选择本月之前的日期 <DatePicker type="date" :options="options3" format="yyyy ...