当前位置:   article > 正文

bzoj 4242: 水壶 最小生成树&树上倍增_bzoj4242

bzoj4242

       为了降低AC率这道题目我各种花样作死爆OJ,最后还是和标算改得差不多了。。。

       显然答案应该为建筑物构成的最小生成树中,两点间的最大路径;那么只要得到这棵最小生成树就可以用倍增在O(QlogN)的时间内得到答案了。因此关键是求最小生成树。

       注意到是平面图,因此考虑用bfs求最小生成树。直接以每个建筑为原点拓展显然不行,那么我们可以把每个建筑都加入队列一起拓展,那么对于一个点,一定会被其中的一个建筑第一次拓展到,则令这个点为该建筑的“势力范围”。那么对于两个建筑“势力范围”边界上接触的点,显然这两个建筑之间的边只能有边界上的点得到。因此就用这些点连边即可。显然这样得到是最小生成树。

       然后用倍增求lca的方法得到答案即可。

AC代码如下:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #define N 2005
  5. #define M 200005
  6. using namespace std;
  7. int n,m,pt,cas,tot,cnt,fa[M][18],g[M][18],bin[25],anc[M],fst[M],pnt[N*N],nxt[N*N],len[N*N];
  8. int dep[M],h[N*N][2],d[N][N],blg[N][N]; bool mp[N][N];
  9. const int dx[4]={-1,1,0,0},dy[4]={0,0,-1,1};
  10. int read(){
  11. int x=0; char ch=getchar();
  12. while (ch<'0' || ch>'9') ch=getchar();
  13. while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
  14. return x;
  15. }
  16. struct grapg{
  17. int fst[N*N];
  18. void add(int x,int y,int z){
  19. pnt[++tot]=y; nxt[tot]=fst[x]; len[tot]=z; fst[x]=tot;
  20. }
  21. }g1,g2;
  22. int getanc(int x){ return (x==anc[x])?x:anc[x]=getanc(anc[x]); }
  23. void dfs(int x){
  24. int p,i;
  25. for (i=1; bin[i]<=dep[x]; i++){
  26. fa[x][i]=fa[fa[x][i-1]][i-1];
  27. g[x][i]=max(g[x][i-1],g[fa[x][i-1]][i-1]);
  28. }
  29. for (p=g2.fst[x]; p; p=nxt[p]){
  30. int y=pnt[p];
  31. if (y!=fa[x][0]){
  32. fa[y][0]=x; g[y][0]=len[p];
  33. dep[y]=dep[x]+1; dfs(y);
  34. }
  35. }
  36. }
  37. int qry(int x,int y){
  38. if (getanc(x)!=getanc(y)) return -1;
  39. if (dep[x]<dep[y]) swap(x,y); int tmp=dep[x]-dep[y],i,ans=0;
  40. for (i=0; bin[i]<=tmp; i++)
  41. if (tmp&bin[i]){ ans=max(ans,g[x][i]); x=fa[x][i]; }
  42. for (i=17; i>=0; i--)
  43. if (fa[x][i]!=fa[y][i]){
  44. ans=max(ans,max(g[x][i],g[y][i]));
  45. x=fa[x][i]; y=fa[y][i];
  46. }
  47. if (x!=y) ans=max(ans,max(g[x][0],g[y][0])); return ans;
  48. }
  49. int main(){
  50. m=read(); n=read(); pt=read(); cas=read();
  51. int i,j; char ch=getchar();
  52. bin[0]=1; for (i=1; i<=18; i++) bin[i]=bin[i-1]<<1;
  53. for (i=1; i<=m; i++){
  54. while (ch!='.' && ch!='#') ch=getchar();
  55. for (j=1; j<=n; j++,ch=getchar())
  56. mp[i][j]=(ch=='.');
  57. }
  58. int head=0,tail=0,x,y,z;
  59. memset(d,-1,sizeof(d));
  60. for (i=1; i<=pt; i++){
  61. h[++tail][0]=x=read(); h[tail][1]=y=read();
  62. blg[x][y]=i; d[x][y]=0;
  63. anc[i]=i;
  64. }
  65. while (head<tail){
  66. x=h[++head][0]; y=h[head][1]; z=blg[x][y];
  67. for (i=0; i<4; i++){
  68. int u=x+dx[i],v=y+dy[i];
  69. if (u>0 && u<=m && v>0 && v<=n && mp[u][v])
  70. if (d[u][v]==-1){
  71. d[u][v]=d[x][y]+1; blg[u][v]=z;
  72. h[++tail][0]=u; h[tail][1]=v;
  73. } else if (z!=blg[u][v]) g1.add(d[u][v]+d[x][y],z,blg[u][v]);
  74. }
  75. }
  76. for (i=0; i<m*n; i++)
  77. for (j=g1.fst[i]; j; j=nxt[j]){
  78. x=getanc(pnt[j]); y=getanc(len[j]);
  79. if (x!=y){
  80. anc[x]=y; g2.add(pnt[j],len[j],i);
  81. g2.add(len[j],pnt[j],i);
  82. }
  83. }
  84. for (i=1; i<=pt; i++)
  85. if (getanc(i)==i){
  86. dep[i]=1; dfs(i);
  87. }
  88. while (cas--) printf("%d\n",qry(read(),read()));
  89. return 0;
  90. }


by lych

2016.3.26

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/368579
推荐阅读
相关标签
  

闽ICP备14008679号