hdu1828 Picture (线段树:扫描线周长)

依然是扫描线,只不过是求所有矩形覆盖之后形成的图形的周长。

容易发现,扫描线中的某一条横边对答案的贡献。

其实就是 加上/去掉这条边之前的答案 和 加上/去掉这条边之后的答案 之差的绝对值

然后横着竖着都做一遍就行了

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #define N 10010
  5 #define ll long long
  6 using namespace std;
  7
  8 int n,sz;
  9 int a[N],cnt[N<<2],sum[N<<2];
 10 struct SQU{
 11     int a1,b1,a2,b2;
 12 }q[N];
 13 struct node{
 14     int l,r,la,ra,h,f;
 15 }sc[N];
 16 int cmp1(node s1,node s2){
 17     if(s1.h!=s2.h) return s1.h<s2.h;
 18     else return s1.f>s2.f;
 19 }
 20 void pushup(int l,int r,int rt)
 21 {
 22     if(cnt[rt]>0) sum[rt]=a[r+1]-a[l];
 23     else if(l==r) sum[rt]=0;
 24     else sum[rt]=sum[rt<<1]+sum[rt<<1|1];
 25 }
 26 void update(int L,int R,int l,int r,int rt,int w)
 27 {
 28     if(L<=l&&r<=R)
 29     {
 30         cnt[rt]+=w;
 31         pushup(l,r,rt);
 32         return;
 33     }
 34     int mid=(l+r)>>1;
 35     if(L<=mid) update(L,R,l,mid,rt<<1,w);
 36     if(R>mid) update(L,R,mid+1,r,rt<<1|1,w);
 37     pushup(l,r,rt);
 38 }
 39 void clr()
 40 {
 41     memset(a,0,sizeof(a));
 42     memset(sc,0,sizeof(sc));
 43     memset(cnt,0,sizeof(cnt));
 44     memset(sum,0,sizeof(sum));
 45 }
 46 int solvex()
 47 {
 48     int ans=0,lst=0;
 49     for(int i=1;i<=n;i++)
 50     {
 51         a[2*i-1]=q[i].a1,a[2*i]=q[i].a2;
 52         sc[2*i-1].l=q[i].a1,sc[2*i].l=q[i].a1;
 53         sc[2*i-1].r=q[i].a2,sc[2*i].r=q[i].a2;
 54         sc[2*i-1].h=q[i].b1,sc[2*i].h=q[i].b2;
 55         sc[2*i-1].f=1,sc[2*i].f=-1;
 56     }
 57     sort(a+1,a+2*n+1);
 58     sz=unique(a+1,a+2*n+1)-(a+1);
 59     sort(sc+1,sc+2*n+1,cmp1);
 60     for(int i=1;i<=2*n;i++)
 61     {
 62         int la=lower_bound(a+1,a+sz+1,sc[i].l)-a;
 63         int ra=lower_bound(a+1,a+sz+1,sc[i].r)-a;
 64         lst=sum[1];
 65         update(la,ra-1,1,sz,1,sc[i].f);
 66         ans+=abs(sum[1]-lst);
 67     }
 68     return ans;
 69 }
 70 int solvey()
 71 {
 72     int ans=0,lst=0;
 73     for(int i=1;i<=n;i++)
 74     {
 75         a[2*i-1]=q[i].b1,a[2*i]=q[i].b2;
 76         sc[2*i-1].l=q[i].b1,sc[2*i].l=q[i].b1;
 77         sc[2*i-1].r=q[i].b2,sc[2*i].r=q[i].b2;
 78         sc[2*i-1].h=q[i].a1,sc[2*i].h=q[i].a2;
 79         sc[2*i-1].f=1,sc[2*i].f=-1;
 80     }
 81     sort(a+1,a+2*n+1);
 82     sz=unique(a+1,a+2*n+1)-(a+1);
 83     sort(sc+1,sc+2*n+1,cmp1);
 84     for(int i=1;i<=2*n;i++)
 85     {
 86         int la=lower_bound(a+1,a+sz+1,sc[i].l)-a;
 87         int ra=lower_bound(a+1,a+sz+1,sc[i].r)-a;
 88         lst=sum[1];
 89         update(la,ra-1,1,sz,1,sc[i].f);
 90         ans+=abs(sum[1]-lst);
 91     }
 92     return ans;
 93 }
 94
 95 int main()
 96 {
 97     //freopen("data.in","r",stdin);
 98     scanf("%d",&n);
 99     for(int i=1;i<=n;i++)
100         scanf("%d%d%d%d",&q[i].a1,&q[i].b1,&q[i].a2,&q[i].b2);
101     int ret=0;
102     ret+=solvex();
103     clr();
104     ret+=solvey();
105     printf("%d\n",ret);
106     return 0;
107 }

原文地址:https://www.cnblogs.com/guapisolo/p/9697021.html

时间: 2024-10-15 09:08:57

hdu1828 Picture (线段树:扫描线周长)的相关文章

hdu 1828 Picture(线段树&amp;扫描线&amp;周长并)

Picture Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2578    Accepted Submission(s): 1363 Problem Description A number of rectangular posters, photographs and other pictures of the same shap

hdu1828 Picture(线段树+离散化+扫描线)两种方法

C - Picture Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or

HDU 1828 Picture 线段树+扫描线

题意:给你一些矩形的左上角点的坐标和右下角点的坐标,求周长并 最显而易见的思路就是对于x轴和y轴做两次扫描线,对于负数的坐标进行离散化.每次增加的值是线段变化量的绝对值.具体写法和求面积并的差不多. #include <cstdio> #include <algorithm> #include <cstring> #include <vector> using namespace std; #define lson rt << 1 , l , m

hdu1828(线段树——矩形周长并)

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1828 分析:与面积不同的地方是还要记录竖的边有几个(num记录),并且当边界重合的时候需要合并(用lbd和rbd表示边界来辅助) 线段树操作:update:区间增减 query:直接取根节点的值 #include <cstdio> #include <cstring> #include <string> #include <cmath> #include <

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

[线段树扫描线][USACO5.5]矩形周长Picture

墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 所有矩形的边界.所有矩形顶点的坐标都是整数. 输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形.接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间). 输出文件只有一个正整数,表示所有矩形的周长. 题解 线段树扫描线  https://www.luogu.org/problemnew/sol

【BZOJ】1382: [Baltic2001]Mars Maps (线段树+扫描线)

1382: [Baltic2001]Mars Maps Time Limit: 5 Sec  Memory Limit: 64 MB Description 给出N个矩形,N<=10000.其坐标不超过10^9.求其面积并 Input 先给出一个数字N,代表有N个矩形. 接下来N行,每行四个数,代表矩形的坐标. Output 输出面积并 Sample Input 2 10 10 20 20 15 15 25 30 Sample Output 225 本以为是傻逼题,没想到不容易啊- 线段树+扫描

BZOJ 4059 Cerc2012 Non-boring sequences 线段树+扫描线

题目大意:定义一个序列为[不无聊的]当且仅当这个序列的任意一个区间都存在一个数只出现过一次,给定一个序列,要求判断这个序列是否是[不无聊的] 定义lasti表示第i个元素上一次出现的位置(第一次出现则为0),nexti表示第i个元素下一次出现的位置(最后一次出现则为n+1),那么这个元素能成为某个区间仅出现一次的数,当且仅当这个区间的左端点在[lasti+1,i]之间,右端点在[i,nexti?1]之间 我们可以将区间的左右端点放在二维平面上,那么一个元素产生的贡献是一个矩形,我们要确定的是所有

HDU 4419 Colourful Rectangle --离散化+线段树扫描线

题意: 有三种颜色的矩形n个,不同颜色的矩形重叠会生成不同的颜色,总共有R,G,B,RG,RB,GB,RGB 7种颜色,问7种颜色每种颜色的面积. 解法: 很容易想到线段树扫描线求矩形面积并,但是如何维护每种颜色的长度着实让我伤透了脑筋.后来看了一位朋友的题解,才幡然醒悟. 开始想到了用二进制表示颜色,R用001表示,G用010表示,B用100表示.那么就可以用十进制1~7表示7种不同颜色了. 维护 cov[rt][1~3] 表示此区间内3种原色各有多少个, Len[rt][i]表示每种颜色的长