zoukankan      html  css  js  c++  java
  • 扫描线

      这个扫描线气死我了,我理解其中思想 却不知道怎么写

    彻底被结构体优先队列搞疯,以前以为在结构体里面重载运算符就是优先队列结构体,发现错误的照样sort。

    我去,这是真的难受 无奈之下写了一个pair套pair再套pair还套pair

    这可是要exs我了,想define F->first 发现不行鬼畜的first 和second 然后 码长很长。

    晕死了,然后蜜汁离散化 然后蜜汁 优先队列。

    在计算代价的时候GG了发现错了。然后 0分。

    发现是不会扫描线的缘故,恶补扫描线。

    花费了我3h也不知道怎么写扫描线,为什么要离散 怎么搞向上延伸的最大距离。

    不会。。。

    针对这道题 题目大意是求各个矩形面积的并。

    我想我 可以 看书。然后不太会。

    学了至少3h 我也不知道为什么可能中间思考了一些关于线段树的细节的问题。

    这道题考虑将其一块一块分解 求面积 首先我们只要 用|x||y|就能求出每一块矩形。

    然后考虑怎么维护x或者y 让x单调 将y放入线段树中 因为y是一个小数所以 考虑离散

    经过多年离散发现 并不是所有的离散都是那三行离散化。

    求出线每次扫描到的地方即可。

     //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<vector>
    #include<ctime>
    #define INF 2147483646
    #define l(x) s[x].l
    #define r(x) s[x].r
    #define c(x) s[x].cnt
    #define sum(x) s[x].len
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline long long read()
    {
        long long x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(long long x)
    {
        x<0?putchar('-'),x=-x:0;
        long long num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int MAXN=1000;
    int n,m,num;
    double real[MAXN];//r存y的真实值 v存y的离散值
    struct wy
    {
        double x,y,z;
        int k;
        bool operator <(const wy &h)const 
        {
            return x<h.x;
        }
    }a[MAXN];
    map<double,int>v;
    struct wy1
    {
        int l,r;
        int cnt;
        double len;
    }s[MAXN];
    void build(int p,int l,int r)
    {
        l(p)=l;r(p)=r;
        sum(p)=0;c(p)=0;
        if(l==r)return;
        int mid=(l+r)>>1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
    }
    void change(int p,int l,int r,int d)
    {
        if(l<=l(p)&&r>=r(p))sum(p)=((c(p)+=d)?real[r(p)+1]-real[l(p)]:0);
        if(l(p)==r(p))return;
        int mid=(l(p)+r(p))>>1;
        if(l<=mid)change(p<<1,l,r,d);
        if(r>mid)change(p<<1|1,l,r,d);
        sum(p)=(c(p)?real[r(p)+1]-real[l(p)]:sum(p<<1)+sum(p<<1|1));
    }
    
    int main()
    {
        //freopen("1.in","r",stdin);
        while(1)
        {
            n=read();
            if(n==0)break;
            for(int i=1;i<=n;i++)
            {
                int k=i<<1;
                double y,z;
                scanf("%lf %lf %lf %lf",&a[k-1].x,&y,&a[k].x,&z);
                real[k-1]=a[k-1].y=a[k].y=y;//先搞一波y值
                real[k]=a[k-1].z=a[k].z=z;
                a[k-1].k=1;
                a[k].k=-1;
            }
            n=n<<1;
            sort(real+1,real+1+n);
            m=unique(real+1,real+1+n)-(real+1);//离散 建一棵线段树
            for(int i=1;i<=m;i++)v[real[i]]=i;
            sort(a+1,a+1+n);//按照x从小到大排序
            double ans=0;
            build(1,1,m-1);//发现线段树存某个点的cnt没有任何意义 
            //应该存一段区间的值 那么我们建m-1个区间即可
            for(int i=1;i<n;i++)
            {
                int y=v[a[i].y],z=v[a[i].z]-1;
                //cout<<y<<' '<<z<<endl;
                change(1,y,z,a[i].k);
                ans+=sum(1)*(a[i+1].x-a[i].x);
                //cout<<sum(1)<<endl;
            }
            printf("Test case #%d
    ",++num);
            printf("Total explored area: %.2lf
    ",ans);
            puts("");
        }
        return 0;
    }
    View Code

    这道题就是我开头吐槽的那道困扰我好久的题目。很气。

    学过扫描线了 然后发现这题并非是线段树 或者说线段树非常难写。

    点开的题解中发现一篇非常简单体现了扫描线的思路(当然和我想的差不多喽)

    差的是对STL multiset 的使用罢了。

    这里使用multiset维护整个扫描线。然后一条一条加即可完成操作!

    非常巧妙的思想!

     //#include<bits/stdc++.h>
    #include<iostream>
    #include<cstdio>
    #include<iomanip>
    #include<cstring>
    #include<string>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<cctype>
    #include<utility>
    #include<set>
    #include<bitset>
    #include<queue>
    #include<stack>
    #include<deque>
    #include<map>
    #include<vector>
    #include<ctime>
    #define INF 2147483646
    #define h(p) t[p].h
    #define l(p) t[p].x
    #define k(p) t[p].k
    using namespace std;
    char buf[1<<15],*fs,*ft;
    inline char getc()
    {
        return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;
    }
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    inline void put(int x)
    {
        x<0?putchar('-'),x=-x:0;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        num==0?putchar('0'):0;
        while(num)putchar(ch[num--]);
        putchar(' ');return;
    }
    const int MAXN=100002;
    int x[MAXN<<2],y[MAXN<<2];
    int n,m,cnt;
    struct wy
    {
        int h,x,k;
    }t[MAXN<<1];
    multiset<int>q;
    int cmp(wy x,wy y)
    {
        if(x.x!=y.x)return x.x<y.x;
        if(x.k!=y.k)return x.k<y.k;
        if(x.k==1)return x.h>y.h;
        return x.h<y.h;
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();
        for(int i=1;i<=n;i++)
        {
            int high,xx,yy;
            high=read();xx=read();yy=read();
            ++m,l(m)=xx,h(m)=high,k(m)=1;
            ++m,l(m)=yy,h(m)=high,k(m)=2;
        }
        sort(t+1,t+1+m,cmp);
        q.insert(0);
        for(int i=1;i<=m;i++)
        {
            int mx=*q.rbegin();
            if(k(i)==1)
            {
                if(h(i)>mx)
                {
                    ++cnt;x[cnt]=l(i);y[cnt]=mx;
                    ++cnt;x[cnt]=l(i);y[cnt]=h(i);
                    q.insert(h(i));
                }
                else q.insert(h(i));
            }
            if(k(i)==2)
            {
                if(h(i)==mx&&q.count(mx)==1)
                {
                    q.erase(mx);
                    ++cnt;x[cnt]=l(i);y[cnt]=mx;
                    ++cnt;x[cnt]=l(i);y[cnt]=*q.rbegin();
                }
                else q.erase(q.find(h(i)));
            }
        }
        put(cnt);puts("");
        for(int i=1;i<=cnt;i++)put(x[i]),put(y[i]),puts("");
        return 0;
    }
    View Code

    既见君子,云胡不喜!

  • 相关阅读:
    Other.ini配置文件解读以及大众评委打分的最后得分两种模式选择及解析选项解释
    大作业练习:用Asp.net Mvc4做一个:学生考试成绩管理系统-简易版
    网络营销实施步骤及疑难问题汇编
    Web前端知识汇编收集B
    Web前端知识汇编收集A
    FlexItem 多行测试
    Last Work-随机出题加法游戏
    Android DisplayMetrics类获取屏幕大小
    Java简介
    Failed to resolve:junit:junit:4.12
  • 原文地址:https://www.cnblogs.com/chdy/p/10415142.html
Copyright © 2011-2022 走看看