• 【hdu1255】线段树求矩形面积交


    题意大概就是上图这个样子。<=100组测试数据,每组<=1000个矩形。

    题解:

    这个问题怎么解决。。做了上一题矩形面积并应该就会了。。

    对于每个节点维护3个值:

    cnt:该节点所代表的这条线段被覆盖了多少次

    len1:该节点所管理区间中被覆盖了>=1次的线段总长

    len2:该节点所管理区间中被覆盖了>=2次的线段总长

    为什么要维护两个呢?因为要是只维护len2,那子树中要是有个覆盖了一次的,然后该节点覆盖一次,那么怎么更新len2丫。。

    怎么更新?

     1 void upd(int x)
     2 {
     3     int lc=t[x].lc,rc=t[x].rc;
     4     if(t[x].cnt>=2) //如果该点被覆盖了两次
     5         t[x].len1=t[x].len2=t[x].rl;//len1和len2=该节点所代表线段的长度
     6     if(t[x].cnt==1)//如果该点只被覆盖了一次
     7     {
     8         t[x].len1=t[x].rl;//len1=全长
     9         t[x].len2=t[lc].len1+t[rc].len1;//孩子中有些只被覆盖了一次的变成覆盖了两次
    10     }
    11     if(t[x].cnt==0)//如果没被覆盖,那就直接上传更新。
    12     {
    13         t[x].len1=t[lc].len1+t[rc].len1;
    14         t[x].len2=t[lc].len2+t[rc].len2;
    15     }
    16 }

    一开始我在纠结一种情况:一个节点现在被覆盖一次,它的子树中原本有个节点被覆盖了一次,那么怎么更新?维护一个从根节点往下的sum值吗?

    后来我发现该节点的len2可以直接用孩子的len1更新就好。

    弱弱弱弱弱弱弱弱弱弱弱弱弱弱弱弱

      1 #include<cstdio>
      2 #include<cstdlib>
      3 #include<cstring>
      4 #include<cmath>
      5 #include<iostream>
      6 #include<algorithm>
      7 using namespace std;
      8 
      9 const int N=11000,INF=(int)1e9;
     10 double z[N][4];
     11 struct point{
     12     double d;
     13     int x,y;
     14 }p[2*N];
     15 struct node{
     16     int x0,x1,d;
     17     double y;
     18 }a[N];
     19 struct trnode{
     20     int l,r,lc,rc,cnt,lazy;
     21     double rl,len1,len2;
     22     //len1以x为根的子树中表示被覆盖了>=1次的线段长度,len2表示以x为根的子树中被覆盖了>=2次的线段的长度
     23 }t[2*N];
     24 double num[N];
     25 int n,tl,pl,al;
     26 
     27 int minn(int x,int y){return x<y ? x:y;}
     28 int maxx(int x,int y){return x>y ? x:y;}
     29 bool cmp_d(point x,point y){return x.d<y.d;}
     30 bool cmp_y(node x,node y){return x.y<y.y;}
     31 
     32 int bt(int l,int r)
     33 {
     34     int x=++tl;
     35     t[x].l=l;t[x].r=r;
     36     t[x].lc=t[x].rc=0;
     37     t[x].cnt=0;t[x].lazy=0;
     38     t[x].len1=t[x].len2=0;
     39     t[x].rl=num[r+1]-num[l];
     40     if(l<r)
     41     {
     42         int mid=(l+r)/2;
     43         t[x].lc=bt(l,mid);
     44         t[x].rc=bt(mid+1,r);
     45     }
     46     return x;
     47 }
     48 
     49 void upd(int x)
     50 {
     51     int lc=t[x].lc,rc=t[x].rc;
     52     if(t[x].cnt>=2) //如果该点被覆盖了两次
     53         t[x].len1=t[x].len2=t[x].rl;//len1和len2=该节点所代表线段的长度
     54     if(t[x].cnt==1)//如果该点只被覆盖了一次
     55     {
     56         t[x].len1=t[x].rl;//len1=全长
     57         t[x].len2=t[lc].len1+t[rc].len1;//孩子中有些只被覆盖了一次的变成覆盖了两次
     58     }
     59     if(t[x].cnt==0)//如果没被覆盖,那就直接上传更新。
     60     {
     61         t[x].len1=t[lc].len1+t[rc].len1;
     62         t[x].len2=t[lc].len2+t[rc].len2;
     63     }
     64 }
     65 
     66 void change(int x,int l,int r,int d,int sum)
     67 {
     68     if(t[x].l==l && t[x].r==r) 
     69     {
     70         t[x].cnt+=d;
     71         upd(x);
     72         return ;
     73     }
     74     int lc=t[x].lc,rc=t[x].rc,mid=(t[x].l+t[x].r)/2;
     75     if(r<=mid) change(lc,l,r,d,sum+t[x].cnt);
     76     else if(l>mid) change(rc,l,r,d,sum+t[x].cnt);
     77     else
     78     {
     79         change(lc,l,mid,d,sum+t[x].cnt);
     80         change(rc,mid+1,r,d,sum+t[x].cnt);
     81     }
     82     upd(x);
     83 }
     84 
     85 void output()
     86 {
     87     for(int i=1;i<=tl;i++)
     88         printf("l = %d  r = %d  cnt = %d  len1  = %lf  len2 = %lf  rl = %lf 
    ",t[i].l,t[i].r,t[i].cnt,t[i].len1,t[i].len2,t[i].rl);
     89 }
     90 
     91 int main()
     92 {
     93     freopen("a.in","r",stdin);
     94     int T;
     95     scanf("%d",&T);
     96     while(T--)
     97     {
     98         scanf("%d",&n);
     99         if(n==0) break;
    100         int x,mx;pl=0;tl=0;al=0;t[0].len1=t[0].len2=0;
    101         for(int i=1;i<=n;i++)
    102         {
    103             for(int j=0;j<=3;j++) 
    104             {
    105                 scanf("%lf",&z[i][j]);
    106                 if(j%2==0) p[++pl].d=z[i][j],p[pl].x=i,p[pl].y=j;
    107             }
    108         }
    109         sort(p+1,p+1+pl,cmp_d);
    110         mx=0;p[0].d=INF;
    111         for(int i=1;i<=pl;i++)
    112         {
    113             if(p[i].d!=p[i-1].d) mx++,num[mx]=p[i].d;
    114             z[p[i].x][p[i].y]=mx;
    115         }
    116         bt(1,mx-1);//debug n个节点只有n-1条线段
    117         for(int i=1;i<=n;i++)
    118         {
    119             if(z[i][1]<z[i][3]) swap(z[i][1],z[i][3]);
    120             if(z[i][0]>z[i][2]) swap(z[i][0],z[i][2]);
    121             a[++al].x0=z[i][0];a[al].x1=z[i][2];a[al].y=z[i][1];a[al].d=-1;
    122             a[++al].x0=z[i][0];a[al].x1=z[i][2];a[al].y=z[i][3];a[al].d=1;
    123         }
    124         sort(a+1,a+1+al,cmp_y);
    125         double w,h,ans=0;
    126         change(1,a[1].x0,a[1].x1-1,a[1].d,0);
    127         for(int i=2;i<=al;i++)
    128         {
    129             h=a[i].y-a[i-1].y;
    130             w=t[1].len2;
    131             ans+=w*h;
    132             change(1,a[i].x0,a[i].x1-1,a[i].d,0);
    133         }
    134         printf("%.2lf
    ",ans);
    135     }
    136     return 0;
    137 }
  • 相关阅读:
    使用AChartEngine画图,项目总结
    Windows系统安装实验报告
    Linux系统安装实验报告
    vm虚拟机详细安装步骤
    L3-010. 是否完全二叉搜索树
    第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛
    L2-021. 点赞狂魔
    L2-020. 功夫传人
    L2-019. 悄悄关注
    L2-017. 人以群分
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/6025189.html
Copyright © 2020-2023  润新知