• [9018_1963][IOI_1998]Picture


    题目描述

    N(N<5000) 张矩形的海报,照片和其他同样形状的图片贴在墙上。它们的边都是垂直的或水平的。每个矩形可以部分或者全部覆盖其他矩形。所有的矩形组成的集合的轮廓称为周长。写一个程序计算周长。

    所有矩形的顶点坐标均为整数。所有的坐标都在 [-10000,10000] 的范围内,并且任何一个矩形面积都为整数。结果的值可能需要 32 位有符号整数表示。

    输入

    第1行: N,张贴在墙上的矩形的数目。 第 2..N+1行 接下来的N行中,每行都有两个点的坐标,分别是矩形的左下角坐标和右上角坐标。每一个坐标由 X 坐标和 Y 坐标组成。

    输出

    只有一行,为一个非负整数,表示输入数据中所有矩形集合的轮廓长度。

    样例输入

    7
    -15 0 5 10
    -5 8 20 25
    15 -4 24 14
    0 -6 16 4
    2 15 10 22
    30 10 36 20
    34 0 40 16

    样例输出

    228


    题解:

    线段树+扫描线

    对于每条线段,分横竖考虑,排序,坐标第一关键字,左右第2关键字

    对于矩形左边线段,先统计这条线段区域0的个数,在把线段树中这条线段覆盖的区域+1,右边反过来

    一定要记得右端点-1(因为题目给的是点,实际上是区间)

    例如1,3。其实只覆盖2个区间(1,2;2,3)

    #include<iostream> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    using namespace std; 
    struct data1{ 
        int l,r,k,p; 
    }x[10001],y[10001]; 
    struct data2{ 
        int x,s,l,r,la; 
    }tree[80001]; 
    int n; 
    bool cmp(data1 a,data1 b) 
    { 
        if(a.k==b.k)return a.p>b.p; 
        return a.k<b.k; 
    } 
    void down(int x) 
    { 
        tree[x*2].x+=tree[x].la; 
        tree[x*2].la+=tree[x].la; 
        tree[x*2+1].x+=tree[x].la; 
        tree[x*2+1].la+=tree[x].la; 
        tree[x].la=0; 
    } 
    void up(int x) 
    { 
        tree[x].x=min(tree[x*2].x,tree[x*2+1].x); 
        if(tree[x*2].x==tree[x*2+1].x)tree[x].s=tree[x*2].s+tree[x*2+1].s; 
        if(tree[x*2].x<tree[x*2+1].x)tree[x].s=tree[x*2].s; 
        if(tree[x*2].x>tree[x*2+1].x)tree[x].s=tree[x*2+1].s; 
    } 
    void init(int x,int l,int r) 
    { 
        tree[x].l=l;tree[x].r=r;tree[x].la=0;tree[x].x=0; 
        if(l==r){tree[x].s=1;return;} 
        init(x*2,l,(l+r)/2);init(x*2+1,(l+r)/2+1,r); 
        up(x); 
    } 
    void add(int x,int l,int r,int k) 
    { 
        if(tree[x].l==l&&tree[x].r==r){tree[x].x+=k;tree[x].la+=k;return;} 
        down(x); 
        int mid=(tree[x].l+tree[x].r)/2; 
        if(r<=mid)add(x*2,l,r,k); 
        else if(l>mid)add(x*2+1,l,r,k); 
        else {add(x*2,l,mid,k);add(x*2+1,mid+1,r,k);} 
        up(x); 
    } 
    void query(int x,int l,int r,int &ansx,int &anss) 
    { 
        if(tree[x].l==l&&tree[x].r==r) 
        { 
            if(ansx==tree[x].x)anss+=tree[x].s; 
            if(tree[x].x<ansx)anss=tree[x].s; 
            ansx=min(ansx,tree[x].x);return; 
        } 
        down(x); 
        int mid=(tree[x].l+tree[x].r)/2; 
        if(r<=mid)query(x*2,l,r,ansx,anss); 
        else if(l>mid)query(x*2+1,l,r,ansx,anss); 
        else {query(x*2,l,mid,ansx,anss);query(x*2+1,mid+1,r,ansx,anss);} 
    } 
    int main() 
    { 
        scanf("%d",&n); 
        for(int i=1;i<=n;i++) 
        { 
            int _x1,_y1,_x2,_y2; 
            scanf("%d%d%d%d",&_x1,&_y1,&_x2,&_y2); 
            _x1+=10000;_x2+=10000;_y1+=10000;_y2+=10000; 
            y[i*2-1].l=_x1;y[i*2-1].r=_x2-1;y[i*2-1].k=_y1;y[i*2-1].p=1; 
            y[i*2].l=_x1;y[i*2].r=_x2-1;y[i*2].k=_y2;y[i*2].p=-1; 
            x[i*2-1].l=_y1;x[i*2-1].r=_y2-1;x[i*2-1].k=_x1;x[i*2-1].p=1; 
            x[i*2].l=_y1;x[i*2].r=_y2-1;x[i*2].k=_x2;x[i*2].p=-1; 
        } 
        n*=2;int ans=0; 
        sort(x+1,x+n+1,cmp);sort(y+1,y+n+1,cmp); 
        init(1,0,20000); 
        for(int i=1;i<=n;i++) 
        { 
            if(x[i].p==-1)add(1,x[i].l,x[i].r,-1); 
            int anss=0,ansx=999999999;query(1,x[i].l,x[i].r,ansx,anss); 
            if(x[i].p==1)add(1,x[i].l,x[i].r,1); 
            if(ansx==0)ans+=anss; 
        } 
        init(1,0,20000); 
        for(int i=1;i<=n;i++) 
        { 
            if(y[i].p==-1)add(1,y[i].l,y[i].r,-1); 
            int anss=0,ansx=999999999;query(1,y[i].l,y[i].r,ansx,anss); 
            if(y[i].p==1)add(1,y[i].l,y[i].r,1); 
            if(ansx==0)ans+=anss; 
        } 
        cout<<ans;return 0; 
    }  
  • 相关阅读:
    Shell——2
    Vim-快捷命令
    Shell——1
    linux命令笔记
    小飞机 + zeal 安装
    linux 环境下 假设被cc攻击,请从linux日志文件找出黑客ip地址
    日志文件例子
    最大子列和的四种方法,时间复杂度递减,直至为线性复杂度
    递归很耗内存+多项式求值的两种方法+c语言计时方法
    线代 第六章 二次型
  • 原文地址:https://www.cnblogs.com/lher/p/6539214.html
Copyright © 2020-2023  润新知