• 亚特兰蒂斯--扫描线


    题意:

    输入格式

    输入包含多组测试用例。

    对于每组测试用例,第一行包含整数 n,表示总的地图数量。

    接下来 n行,描绘了每张地图,每行包含四个数字 x1,y1,x2,y2(不一定是整数),(x1,y1)和 (x2,y2)分别是地图的左上角位置和右下角位置。

    注意,坐标轴 x 轴从上向下延伸,y 轴从左向右延伸。

    当输入用例 n=0时,表示输入终止,该用例无需处理。

    输出格式

    每组测试用例输出两行。

    第一行输出 Test case #k,其中 kk 是测试用例的编号,从 1 开始。

    第二行输出 Total explored area: a,其中 a 是总地图面积(即此测试用例中所有矩形的面积并,注意如果一片区域被多个地图包含,则在计算总面积时只计算一次),精确到小数点后两位数。

    输入样例:

    1. 2
    2. 10 10 20 20
    3. 15 15 25 25.5
    4. 0

    输出样例:

    1. Test case #1
    2. Total explored area: 180.00

    代码:

    在y方向上建立线段树维护,扫到矩形左边的边时对应区间加1,扫到右边的边对应区间时-1。将所有的y坐标保存到一个vector中,然后离散化,在线段树中每个点都代表一个线段,比如1代表[y1,y2],2代表[y2,y3],[1,4]代表[y1,y5]都被覆盖了,n个点对应n-1个线段,建树时建立build(1,0,n-2)或build(1,1,n-1)

    扫描线每次查询都是查询整个区间被覆盖的长度(tr[1].sum),故查询操作不需要pushdown

    进行修改时,当一个结点被覆盖次数大于1,该节点对应区间被覆盖的长度就是它所对应的长度,当它为覆盖次数为0,该节点对应区间被覆盖的长度为它左孩子被覆盖的长度加右孩子被覆盖的长度,如果是叶子节点的覆盖次数为0,它对应的被覆盖的长度就是0。一个结点的覆盖次数加1,后面一定对应着减1,减1之前也一定有加1,有了前面的操作和限制,修改操作也是不需要pushdown的。

    1. #include
    2. using namespace std;
    3. const int N=1e5+10;
    4. int n;
    5. typedef struct Segment{
    6. double x;
    7. double y1,y2;
    8. int k;
    9. }Segment;
    10. Segment seg[N*2];
    11. typedef struct Node{
    12. int l,r;
    13. int cnt;//当前区间对象对应区间被覆盖的次数
    14. double sum;//当前区间对象对应区间被覆盖的长度
    15. }Node;
    16. Node tr[N*4];
    17. vector<double> vc;
    18. bool cmp(Segment a,Segment b){
    19. return a.x
    20. }
    21. void init(){
    22. vc.clear();
    23. }
    24. int find(double x){
    25. return lower_bound(vc.begin(),vc.end(),x)-vc.begin();
    26. }
    27. void build(int u,int l,int r){
    28. tr[u].l=l,tr[u].r=r;
    29. tr[u].sum=0,tr[u].cnt=0;
    30. if(l==r){
    31. return ;
    32. }
    33. int mid=(l+r)>>1;
    34. build(u<<1,l,mid);
    35. build(u<<1|1,mid+1,r);
    36. }
    37. void update(int u){
    38. if(tr[u].cnt>0)
    39. tr[u].sum=vc[tr[u].r+1]-vc[tr[u].l];
    40. else if(tr[u].l==tr[u].r)//叶子节点
    41. tr[u].sum=0;
    42. else
    43. tr[u].sum=tr[u<<1].sum+tr[u<<1|1].sum;
    44. }
    45. void modify(int u,int l,int r,int k){
    46. if(tr[u].l>=l&&tr[u].r<=r){
    47. tr[u].cnt+=k;
    48. update(u);
    49. return ;
    50. }
    51. int mid=(tr[u].l+tr[u].r)>>1;
    52. if(l<=mid)
    53. modify(u<<1,l,r,k);
    54. if(r>mid)
    55. modify(u<<1|1,l,r,k);
    56. update(u);
    57. }
    58. double query(){
    59. return tr[1].sum;
    60. }
    61. int main(){
    62. double x1,y1,x2,y2;
    63. int tc=0;
    64. while(1){
    65. tc++;
    66. scanf("%d",&n);
    67. if(n==0)
    68. break;
    69. init();
    70. int j=0;
    71. for(int i=1;i<=n;i++){
    72. scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
    73. seg[++j]={x1,y1,y2,1};
    74. seg[++j]={x2,y1,y2,-1};
    75. vc.push_back(y1);
    76. vc.push_back(y2);
    77. }
    78. sort(seg+1,seg+j+1,cmp);
    79. sort(vc.begin(),vc.end());
    80. vc.erase(unique(vc.begin(),vc.end()),vc.end());
    81. int num=vc.size()-1;
    82. build(1,0,num-1);
    83. double nx,ny,ans=0;
    84. int l,r;
    85. for(int i=1;i<=2*n;i++){
    86. if(i!=1)
    87. nx=seg[i].x-seg[i-1].x;
    88. else
    89. nx=0;
    90. ny=query();
    91. ans+=nx*ny;
    92. l=find(seg[i].y1),r=find(seg[i].y2);
    93. modify(1,l,r-1,seg[i].k);
    94. }
    95. printf("Test case #%d\n",tc);
    96. printf("Total explored area: %.2lf\n\n",ans);
    97. }
    98. return 0;
    99. }

  • 相关阅读:
    k8s1.24.3搭建
    如何系统地去学python
    使用Nginx可视化管理工具+Cpolar在本地搭建服务器并实现远程访问【内网穿透】
    内核实战教程第四期 _ 带你走进数据库 SQL 引擎
    用动态规划算法均分纸牌
    多线程之任务调度线程池
    Windows系统/Linux系统修改远程连接端口号
    如何用CRM软件系统管理企业客户
    hive_学习--基本操作
    查找浏览器中保存的密码
  • 原文地址:https://blog.csdn.net/weixin_45772744/article/details/126032293