T1
改题时遇到的问题:
1.搜索时只有树才可以dfs(int x,int f)
2.注意开long long!!!!
题解:
思路不难想(可我考场上还是没想出来),问最小距离的最大值,显然是个二分答案,考虑check(两点之间的距离),上边界和下边界分别抽象成一个点,能不能到,就是看路径上有没有完全阻断的路,那么就可以将每个点按照ans/2的半径作圆,如果有交集就将其连边,那么就从上边界开始dfs,若能找到下边界说明不行,剪枝:先将k个点按照横坐标升序排列,建边的时候如果距离>ans就不用建边了
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdlib> 6 #include<algorithm> 7 #define R register 8 using namespace std; 9 inline int read() 10 { 11 int x=0;char ch=getchar(); 12 while(ch>'9'||ch<'0')ch=getchar(); 13 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 14 return x; 15 } 16 const int maxn=6005; 17 const double eps=1e-8; 18 int n,m,k; 19 struct node{ 20 int v,nxt; 21 }e[maxn*maxn];int h[maxn],nu; 22 void add(int x,int y) 23 { 24 e[++nu].v=y; 25 e[nu].nxt=h[x]; 26 h[x]=nu; 27 } 28 struct poin{ 29 long long x,y; 30 }p[maxn]; 31 bool cmp(poin a,poin b){return (a.x==b.x)?a.y<b.y:a.x<b.x;} 32 inline double cal(int i,int j){return (p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y);} 33 int v[maxn]; 34 int dfs(int x) 35 { 36 if(x==k+1)return 0; 37 v[x]=1; 38 for(int i=h[x];i;i=e[i].nxt) 39 { 40 int y=e[i].v; 41 if(v[y])continue; 42 if(!dfs(y))return 0; 43 } 44 return 1; 45 } 46 inline int valid(double nw) 47 { 48 memset(v,0,sizeof v); 49 memset(h,0,sizeof h); 50 nu=0; 51 for(int i=1;i<=k;++i) 52 { 53 if(1.0*p[i].y>1.0*m-nw)add(0,i),add(i,0); 54 if(1.0*p[i].y<nw)add(k+1,i),add(i,k+1); 55 for(int j=i+1;j<=k;++j) 56 { 57 if(1.0*(p[j].x-p[i].x)>nw)break; 58 if(cal(i,j)<nw*nw) 59 add(i,j),add(j,i); 60 } 61 } 62 return dfs(0); 63 } 64 int main() 65 { 66 //freopen("starway9.in","r",stdin); 67 n=read(),m=read(),k=read(); 68 for(R int i=1;i<=k;++i) 69 p[i].x=read(),p[i].y=read(); 70 sort(p+1,p+k+1,cmp); 71 double l=0.0,r=1.0*m; 72 while(r-l>1e-8) 73 { 74 R double mid=(l+r)/2.0; 75 if(valid(mid)) l=mid; 76 else r=mid-eps; 77 } 78 printf("%.9lf ",l/2.0); 79 } 80 /* 81 g++ 1.cpp -o 1 82 ./1 83 10 5 2 84 1 1 85 2 3 86 87 */
正解:最小生成树,将k个点和上下边界都互相连边,从边界开始跑prim, 由于不断加入的是这个点到已经生成的树上权值最小的边,所以这些边不断地取max,找到另一边界后就可以break了,此时已将在原图上建出一条连接两边界的链了,并且都是最小值,那这其中的max就是答案
T3
原式可以看作是斜率的式子,提个负号,那么就是这个点到其祖先中斜率最大的那个,维护一个凸包(就是后面的斜率都比上一个大),这样在处理一个节点时,比较这个节点和栈顶元素,如果不满足大于即不能是凸包,就不断pop,直到并用其更新ans值,注意回溯时要重新放回去,这能拿80,
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 using namespace std; 6 #define int long long 7 inline int read() 8 { 9 int x=0;char ch=getchar(); 10 while(ch>'9'||ch<'0')ch=getchar(); 11 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 12 return x; 13 } 14 inline double min(double x,double y){return x<y?x:y;} 15 const int maxn=500005; 16 int n,c[maxn],fa[maxn],dep[maxn]; 17 int sta[maxn],top=0; 18 double ans[maxn]; 19 struct node{ 20 int v,nxt; 21 }e[maxn];int h[maxn],nu; 22 void add(int x,int y) 23 { 24 e[++nu].v=y; 25 e[nu].nxt=h[x]; 26 h[x]=nu; 27 } 28 inline double cal(int i,int j) 29 { 30 return 1.0*(double)(c[i]-c[j])/(double)(dep[i]-dep[j]); 31 } 32 int num=0; 33 int sta2[maxn],top2; 34 void dfs(int x) 35 { 36 int down=top2; 37 while(x!=1&&top>=2&&(cal(x,sta[top])<cal(sta[top],sta[top-1]))) 38 sta2[++top2]=sta[top--]; 39 ans[x]=-1.0*cal(x,sta[top]); 40 sta[++top]=x; 41 for(int i=h[x];i;i=e[i].nxt) 42 { 43 int y=e[i].v; 44 dep[y]=dep[x]+1; 45 dfs(y); 46 } 47 --top; 48 while(top2>down) 49 sta[++top]=sta2[top2--]; 50 return; 51 } 52 signed main() 53 { 54 //freopen("data","r",stdin); 55 n=read(); 56 for(int i=1;i<=n;++i)c[i]=read(); 57 for(int i=2;i<=n;++i)fa[i]=read(),add(fa[i],i); 58 dep[1]=1; 59 dfs(1); 60 for(int i=2;i<=n;++i) 61 printf("%.10lf ",ans[i]); 62 } 63 /* 64 g++ 1.cpp -o 1 65 ./1 66 67 8 68 31516 11930 18726 12481 79550 63015 64275 7608 69 1 1 2 4 2 4 5 70 */
再用上链表实现的倍增思路
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<cstring> 5 using namespace std; 6 #define int long long 7 inline int read() 8 { 9 int x=0;char ch=getchar(); 10 while(ch>'9'||ch<'0')ch=getchar(); 11 while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} 12 return x; 13 } 14 inline double min(double x,double y){return x<y?x:y;} 15 const int maxn=500005; 16 int n,c[maxn],dep[maxn],pre[maxn][25],fa[maxn]; 17 double ans[maxn]; 18 struct node{ 19 int v,nxt; 20 }e[maxn];int h[maxn],nu; 21 void add(int x,int y) 22 { 23 e[++nu].v=y; 24 e[nu].nxt=h[x]; 25 h[x]=nu; 26 } 27 inline double cal(int i,int j){return 1.0*(double)(c[i]-c[j])/(double)(dep[i]-dep[j]);} 28 int que[maxn],fro=1,bac=0; 29 void bfs() 30 { 31 que[++bac]=1; 32 while(fro<=bac) 33 { 34 int x=que[fro++]; 35 dep[x]=dep[fa[x]]+1; 36 int y=fa[x]; 37 for(int j=20;j>=0;--j) 38 if(pre[pre[y][j]][0]&&cal(pre[y][j],pre[pre[y][j]][0])>cal(x,pre[y][j]))y=pre[y][j]; 39 if(pre[y][0]&&cal(y,pre[y][0])>cal(x,y))y=pre[y][0]; 40 pre[x][0]=y; 41 ans[x]=-1.0*cal(x,y); 42 for(int j=1;j<=20;++j) 43 pre[x][j]=pre[pre[x][j-1]][j-1]; 44 for(int i=h[x];i;i=e[i].nxt) 45 que[++bac]=e[i].v; 46 } 47 } 48 signed main() 49 { 50 //freopen("data","r",stdin); 51 n=read(); 52 for(int i=1;i<=n;++i)c[i]=read(); 53 for(int i=2;i<=n;++i)fa[i]=read(),add(fa[i],i); 54 bfs(); 55 for(int i=2;i<=n;++i) 56 printf("%.10lf ",ans[i]); 57 } 58 /* 59 g++ 1.cpp -o 1 60 ./1 61 62 8 63 31516 11930 18726 12481 79550 63015 64275 7608 64 1 1 2 4 2 4 5 65 */