【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 \n",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\n",ans);
135     }
136     return 0;
137 }

 

posted @ 2016-11-03 08:20  拦路雨偏似雪花  阅读(298)  评论(0编辑  收藏  举报