【题解】P9544 [湖北省选模拟 2023] 调和 / conduct
题目大意
有一棵
若你获得了
你要选取树上的一个连通块,用连通块上的药材配置出
保证所有
题目分析
首先注意到所有的
只保留每个点的
为了方便,先将
1. 凸包包含原点
充分性显而易见,只需证明必要性。
选取圆上夹角最大的两个点
2. 凸包包含原点
首先由上面可得一定存在某个三角形包含原点,不妨设这个三角形为
对于任意一点
3.可能成为答案的连通块一定是一条链
如果连通块不是一条链,由于存在三个点包含原点,那么一定形如以下结构:
其中包含原点的三角形
注:上面的证明均不考虑一个点、两个点的情况。
接下来考虑点分治,设当前分治重心为
1. 链的两端在不同子树内
设链的两端为
不妨设
由于连通块大小等于
2. 链的一端为
直接在 dfs 的过程中维护
总时间复杂度
代码
随便写的,目前最优解 269ms。
弧长的比较可以转化为角度,用点积比较。
#include<bits/stdc++.h>
using namespace std;
using namespace my_std;
#define eps 1e-12
ll n,head[50050],cnt=0,ans=inf;
ll rt,minn=inf,rsiz,siz[50050],maxdep;
db L[50050],R[50050];
bl ck[50050];
struct edge{
ll nxt,to;
}e[100010];
struct point{
db x,y;
}a[50050],X,XX;
il void add(ll u,ll v){
e[++cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
il db cross(point x,point y){
return x.x*y.y-x.y*y.x;
}
void getroot(ll fa,ll u){
siz[u]=1;
ll maxx=0;
go(u){
ll v=e[i].to;
if(v==fa||ck[v]) continue;
getroot(u,v);
siz[u]+=siz[v];
maxx=max(maxx,siz[v]);
}
maxx=max(maxx,rsiz-siz[u]);
if(minn>maxx){
minn=maxx;
rt=u;
}
}
void dfs(ll fa,ll u,ll dep,db lft,db rgt){
siz[u]=1;
maxdep=max(maxdep,dep);
if(fabs(XX.x-a[u].x)<eps&&fabs(XX.y-a[u].y)<eps) ans=min(ans,dep+1);
else if(cross(X,a[u])>eps){
db tmp=-(X.x*a[u].x+X.y*a[u].y);
if(rgt<=tmp) ans=min(ans,dep+1);
lft=max(lft,tmp);
L[dep]=max(L[dep],tmp);
}
else if(cross(X,a[u])<-eps){
db tmp=-(XX.x*a[u].x+XX.y*a[u].y);
if(lft>=tmp) ans=min(ans,dep+1);
rgt=min(rgt,tmp);
R[dep]=min(R[dep],tmp);
}
go(u){
ll v=e[i].to;
if(v==fa||ck[v]) continue;
dfs(u,v,dep+1,lft,rgt);
siz[u]+=siz[v];
}
}
void solve(ll u){
ck[u]=1;
X=a[u];
XX=(point){-a[u].x,-a[u].y};
maxdep=0;
dfs(0,u,0,-inf,inf);
L[0]=-inf;
R[0]=inf;
fr(i,1,maxdep) L[i]=max(L[i],L[i-1]);
fr(i,1,maxdep) R[i]=min(R[i],R[i-1]);
ll now=maxdep+1;
fr(i,1,maxdep){
while(R[now-1]<=L[i]) now--;
if(now<=maxdep) ans=min(ans,i+now+1);
}
fr(i,1,maxdep) L[i]=-inf;
fr(i,1,maxdep) R[i]=inf;
go(u){
ll v=e[i].to;
if(ck[v]) continue;
rsiz=siz[v];
minn=inf;
getroot(u,v);
solve(rt);
}
}
int main(){
n=read();
fr(i,0,n){
a[i].x=read();
a[i].y=read();
ll tmp=read();
}
fr(i,1,n){
a[i].x-=a[0].x;
a[i].y-=a[0].y;
}
fr(i,2,n){
ll u=read(),v=read();
add(u,v);
add(v,u);
}
fr(i,1,n){
db len=sqrt(a[i].x*a[i].x+a[i].y*a[i].y);
if(fabs(len)<eps){
write(1);
return 0;
}
a[i].x/=len;
a[i].y/=len;
}
rsiz=n;
minn=inf;
getroot(0,1);
fr(i,1,n) L[i]=-inf;
fr(i,1,n) R[i]=inf;
solve(rt);
if(ans==inf) write(-1);
else write(ans);
}