扫描线

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

彻底被结构体优先队列搞疯,以前以为在结构体里面重载运算符就是优先队列结构体,发现错误的照样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('\n');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\n",++num);
        printf("Total explored area: %.2lf\n",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

既见君子,云胡不喜!

posted @ 2019-02-21 20:47  chdy  阅读(491)  评论(0编辑  收藏  举报