zoukankan      html  css  js  c++  java
  • 【BZOJ2731】三角形覆盖问题

    想象一条平行于(y)轴的扫描线,从低往高扫描。如何确定关键高度才能使每两个关键高度之间分割出的图形易于计算呢?
      
      关键高度有:三角形底边高度、三角形上顶点高度、三角形交点的高度。
      
    ​  如此分割,我们会发现,相邻两条扫描线之间的图形,是一个梯形,那么维护每条扫描线上的有效线段长度即可。
      
      如何维护呢?用一个数组(a_i)表示第(i)格被三角形覆盖了多少次,用一个双向链表记录与每一个与当前扫描线相交的三角形的相交的部分([l,r])
      
      扫描线遇到三角形底端时,将(a)([x,x+d-1])全部加上1,往双向链表中加入([x,x+d-1])
      
      上移扫描线一格的方法是:遍历链表,对于每一个元素([l,r]),将(a_r)减1,将(r)减1,如果(l>r),删除这个元素。什么意思呢?上移一格时,每一个相交的三角形的相交部分([l,r])的最右端会变为不相交,即(a_{r})减1,同时使(r)减1。如此操作,三角形在不相交的时候会被自动删除。
      
      鉴于这道题的神秘数据,直接一格一格向上移动就可以过了...... 如果要优化的话,删除掉那些被其他三角形包含的三角形,就能大幅提升速度。
        
      
      

    Code

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    const int N=10005,L=2000005;
    int n;
    int s[L],sum;
    ll ans;
    struct Triangle{int x,y,d;}a[N];
    struct Data{int l,r,pre,nex;}b[N];
    int h,cnt;
    void insert(int x,int y){
        b[++cnt]=(Data){x,y,0,0};
        int th=h;
        h=cnt; b[cnt].nex=th; b[th].pre=cnt;
    }
    void delet(int u){
        int pt=b[u].pre,nt=b[u].nex;                                
        if(pt)
            b[pt].nex=nt; 
        else h=nt;
        if(nt)
            b[nt].pre=pt;
    }
    inline bool cmp(const Triangle &u,const Triangle &v){
        if(u.y!=v.y) return u.y<v.y;
        if(u.x!=v.x) return u.x<v.x;
        return u.d<v.d;
    }
    int main(){
        scanf("%d",&n);
        int topy=0;
        for(int i=1;i<=n;i++){
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
            topy=max(topy,a[i].y+a[i].d);
        }
        sort(a+1,a+1+n,cmp);
        ans=0;
        sum=0;
        int last=0,lasty=0;
        for(int y=0,i=1;y<topy;y++){
            for(;a[i].y==y&&i<=n;i++)
                if(a[i].d){
                    for(int k=0;k<a[i].d;k++){
                        if(!s[a[i].x+k]) sum++;
                        s[a[i].x+k]++;
                    }
                    insert(a[i].x,a[i].x+a[i].d-1);
                }
            last=sum;
            for(int k=h,nk;k;k=nk){
                nk=b[k].nex;
                s[b[k].r]--;
                if(!s[b[k].r]) sum--;
                b[k].r--;
                if(b[k].r<b[k].l) delet(k);
            }
            ans+=1LL*(last+sum);
        }
        printf("%.1lf
    ",1.0*ans/2.0);
        return 0;
    }
    
  • 相关阅读:
    设计模式大赛 -- 大话设计模式
    访问者模式 -- 大话设计模式
    puts的用处
    scanf的使用
    iOS,手势识别简单使用
    iOS,多媒体,地图相关
    iOS,文本输入,键盘相关
    iOS,XMPP本地环境搭建和框架使用
    iOS,自动布局autoresizing和auto layout,VFL语言
    iOS,图片处理
  • 原文地址:https://www.cnblogs.com/RogerDTZ/p/9205046.html
Copyright © 2011-2022 走看看