T1
考试之前波波老师说让我们看看凸包,然后我一看题,觉得T1是个几何题,可能是个凸包,然后就整场没怎么深入思考,实际上并没有太难
二分肯定可以想到,以二分的答案为半径,围着每个星星画个圆,如果两个圆相交了,就用并查集把它们搞在一起,最后如果上下边界属于同一个并查集证明不可行,否则可行
那我们可以想到,限制我们答案的一定是离得最近的两个点,那我们可以以两点之间的欧几里德距离为边权,还是跑最小生成树,答案是最小生成树里最大的边权的一半
1 //下边界标号0上边界标号k+1 2 #include<iostream> 3 #include<cstdio> 4 #include<cmath> 5 #define maxk 6100 6 using namespace std; 7 int n,m,k; 8 double ans; 9 double dis[maxk],x[maxk],y[maxk],vis[maxk]; 10 int main() 11 { 12 scanf("%d%d%d",&n,&m,&k); 13 for(int i=1;i<=k;++i) scanf("%lf%lf",&x[i],&y[i]); 14 dis[k+1]=(double)m; 15 for(int i=1;i<=k;++i) dis[i]=y[i]; 16 for(int i=1;i<=k+1;++i) 17 { 18 int pos; double len=1001000.00000; 19 for(int j=1;j<=k+1;++j) 20 if(!vis[j]&&dis[j]<len) {pos=j; len=dis[j];} 21 vis[pos]=1; ans=max(ans,len); 22 if(pos==k+1) break; 23 for(int j=1;j<=k;++j) 24 { 25 if(!vis[j]) 26 { 27 double le=sqrt((x[j]-x[pos])*(x[j]-x[pos])+(y[j]-y[pos])*(y[j]-y[pos])); 28 dis[j]=min(dis[j],le); 29 } 30 } 31 dis[k+1]=min(dis[k+1],(double)m-y[pos]); 32 } 33 ans=ans/2.0000000; 34 printf("%0.10lf ",ans); 35 return 0; 36 }
T2
是个什么线段树维护单调栈,还没看,最近日常咕题
T3
是个单调栈维护凸包的题,由于在树上,正常进栈弹栈复杂度是$O(n^2)$,所以倍增优化一下就可以了
1 //单调栈维护凸包,一个一个入栈,一个一个弹栈,保证单调升,可倍增优化 2 //通过深搜,进行维护 3 #include<iostream> 4 #include<cstdio> 5 #define maxn 500100 6 using namespace std; 7 int n,js; 8 int head[maxn],to[maxn],xia[maxn]; 9 int c[maxn],deep[maxn],ans[maxn]; 10 int pre[maxn][20]; 11 void add(int x,int y) 12 { 13 to[++js]=y; xia[js]=head[x]; head[x]=js; 14 } 15 double cal(int fa,int son) 16 { 17 double ans=(double)(c[son]-c[fa])/(double)(deep[son]-deep[fa]); 18 return ans; 19 } 20 void dfs(int x) 21 { 22 for(int i=head[x];i;i=xia[i]) 23 { 24 int ls=to[i]; deep[ls]=deep[x]+1; 25 int fa=x; 26 for(int i=19;i>=0;--i) 27 if(pre[fa][i]>1&&cal(pre[fa][i],ls)<=cal(pre[pre[fa][i]][0],ls))//需要弹栈 28 fa=pre[pre[fa][i]][0]; 29 if(fa>1&&cal(ls,fa)<=cal(ls,pre[fa][0])) fa=pre[fa][0]; 30 ans[ls]=fa; pre[ls][0]=fa; 31 for(int i=1;i<=19;++i) pre[ls][i]=pre[pre[ls][i-1]][i-1]; 32 dfs(ls); 33 } 34 } 35 int main() 36 { 37 scanf("%d",&n); 38 for(int i=1;i<=n;++i) scanf("%d",&c[i]); 39 for(int i=2;i<=n;++i) {int x; scanf("%d",&x); add(x,i);} 40 deep[1]=1; dfs(1); 41 for(int i=2;i<=n;++i) printf("%0.10lf ",-cal(ans[i],i)); 42 return 0; 43 }