【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖

传送门

思路:
代码题
如果你已经做过一些扫描线的题目的话,这道题的思路一点都不难想:
不相交的图形→确定它们构成一棵树
如何确定这棵树→扫描线+set
set中的比较函数→圆直接代入方程计算,凸多边形相当于一坨线段,类似圆那样分成上下两部分,直接暴力枚举确定扫描线与哪条线段相交即可
询问坐标中的点→像处理图形那样来确定它们所在的是哪个图形
这样的话问题就转化成在一棵带边权的树上,每次查询两点的路径xor值或修改某一边权
直接链剖就可以了
……
其实上面说的都是些废话,因为做这道题的人肯定都知道思路大致是什么……
【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖_第1张图片
关键就是代码
显然这个题的代码不是那么好写的,下面我就来说说我写这个题的一些经历和体会
码完主体框架(5k+)大概用了1h~1.5h的时间,因为思路比较清楚简单所以没什么停顿
然后调试时发现了一些错误,比如凸多边形的上下部分计算出现问题,原本以为是点权树后来意识到是边权树等等
过了样例交上去发现RE,把数组开大后仍是RE
检查错误,手玩了几个点发现都能过(因为这个题的数据生成器和暴力对于我这个蒟蒻来说真是太TM难写了)
……
后来发现判断凸多边形的左右端点时条件不科学,导致死循环(怪不得内存达到了400MB+)
先说一下,我不是权限号,但之前打luogu的比赛,得到了可以要bzoj数据的奖励= =
于是偷偷要来了数据
这里写图片描述
发现计算交点时出现了玄学的错误,因为我为了避免讨论,在外面放了一个极大的圆
但是要到数据才发现,x,y,r的范围都是 |109| ,而long double的有效位数还不及long long,导致计算溢出,这就很尴尬了
改了下比较函数,又发现开方时出现了负数(??),以为是精度问题,加了个eps扰动,无果,发现差值大约为-0.18..,一度怀疑自己写错了
修改之后终于能跑出结果了,但发现只能过第十组数据,是一个圆套圆的数据(???)
发现又是比较函数的锅,而且似乎又出现了和memory一样的问题, a<b , b<a 同时成立
结果就是一怒之下扔掉set,开始手写splay
【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖_第2张图片
代码也随之增长到了9k
写完以后发现splay和树结构的变量出现了重名(叫你不用namespace)
发现 a<b , b<a 还是没有消除
又是一阵怒改比较函数,终于……
发现数据过了!
【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖_第3张图片
太过兴奋,没仔细看就交上去了,结果
这里写图片描述
感到十分不解,回头用人工二分,发现第45500+行出现了错误
【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖_第4张图片
调了一会,发现还是比较函数的错误,改过来以后在昨天晚自习下课前5min的时候A了
所以想写这道题的同学一定要写好比较函数啊啊啊啊
其实讲道理来说,这道题的思维难度并没有多大,但是对代码能力和思维清晰度要求很高,如果不能将自己的想法准确快速地转化成代码,这和没思路,写不了是同一个结果吧
我觉得这个题如果有人能在考场上得分,那就已经很厉害了,如果能A那就真的是大神……
(用vfk的话说,以上部分实际上是我的A后感)
其实我觉得下面给出的代码很符合知乎某大神的评论(找不到原话了,只能想起大体意思,如果有同学知道的话帮忙评论下谢谢)
“现在国内的大部分OI博客不适合学习,就是想炫耀一下自己A的代码而已”
代码:

#include
#include
#include
#include
#include
#define M 100005
using namespace std;
int n,m,tot,cnt,root,size;
double seg;
int first[M],fa[M<<1],top[M],son[M],siz[M],dep[M],dfn[M],pre[M],tr[M<<2],val[M],ch[M<<1][2],Fa[M];
char in()
{
    char ch=getchar();
    while (ch!='C'&&ch!='Q'&&ch!='P') ch=getchar();
    return ch; 
}
typedef pair<double,double> Point;
Point tmp[M];
struct Poly{
    bool tp;//tp=0 表示凸多边形,opt=1 表示圆 
    int L,val;
    vector up,down;
    double x,y,r;
}a[M];
struct edge{
    int v,w,next;
}e[M<<1];
struct query{
    int opt;//opt=0 表示修改操作,opt=1 表示查询操作
    double x0,y0,x1,y1;
    int l,r;
}b[M];
struct os{
    int tp,id;
    double data;
    bool operator <(const os other)const
    {
        if (data==other.data) return tp>other.tp;
        return data.data;
    }
}c[M<<2];
int dcmp(double x,double y)
{
    if (fabs(x-y)<=1e-7) return 0;
    return x>y?1:-1;
}
double dis(int tp,int id)
{
    if (a[id].tp==1)
        if (tp)
            return a[id].y+sqrt(max(0.0,a[id].r*a[id].r-(seg-a[id].x)*(seg-a[id].x)));
        else
            return a[id].y-sqrt(max(0.0,a[id].r*a[id].r-(seg-a[id].x)*(seg-a[id].x)));
    else
        if (tp)
        {
            int sz=a[id].up.size();
            for (int i=0;i1;++i)
                if (dcmp(a[id].up[i].first,seg)!=1&&dcmp(seg,a[id].up[i+1].first)!=1)
                {
                    if (!dcmp(a[id].up[i].first,a[id].up[i+1].first)) continue;
                    double k=(a[id].up[i+1].second-a[id].up[i].second)/(a[id].up[i+1].first-a[id].up[i].first);
                    return k*(seg-a[id].up[i].first)+a[id].up[i].second;
                }
        }
        else
        {
            int sz=a[id].down.size();
            for (int i=0;i1;++i)
                if (dcmp(a[id].down[i+1].first,seg)!=1&&dcmp(seg,a[id].down[i].first)!=1)
                {
                    if (!dcmp(a[id].down[i].first,a[id].down[i+1].first)) continue;
                    double k=(a[id].down[i].second-a[id].down[i+1].second)/(a[id].down[i].first-a[id].down[i+1].first);
                    return k*(seg-a[id].down[i+1].first)+a[id].down[i+1].second;
                }
        }
}
struct node{
    int tp,id;
    bool operator <(const node other)const
    {
        if (tp<2&&id==n+1) return tp;
        if (other.tp<2&&other.id==n+1) return !other.tp;
        if (tp<2&&other.tp<2&&other.id==id) return tp>other.tp;
        double t1,t2;
        if (tp==2) t1=b[id].y0;
        else if (tp==3) t1=b[id].y1;
        else t1=dis(tp,id);
        if (other.tp==2) t2=b[other.id].y0;
        else if (other.tp==3) t2=b[other.id].y1;
        else t2=dis(other.tp,other.id);
        return dcmp(t1,t2)==1;
    }
    bool operator ==(const node other)const
    {
        return tp==other.tp&&id==other.id;
    }
}Node[M<<1];
void add(int x,int y,int z)
{   
    e[++size]=(edge){y,z,first[x]};first[x]=size;
    e[++size]=(edge){x,z,first[y]};first[y]=size;
}
void rorate(int x,bool f)
{
    int y=fa[x];
    ch[y][!f]=ch[x][f];
    if (ch[x][f])fa[ch[x][f]]=y;
    fa[x]=fa[y];
    if (fa[y])
        if (ch[fa[y]][0]==y) ch[fa[y]][0]=x;
        else ch[fa[y]][1]=x;
    ch[x][f]=y;
    fa[y]=x;
}
void splay(int x,int goal)
{
    for (int y;fa[x]!=goal;)
    {
        y=fa[x];
        if (fa[y]==goal)
            if (ch[y][0]==x) rorate(x,1);
            else rorate(x,0);
        else if (ch[fa[y]][0]==y)
        {
            if (ch[y][0]==x) rorate(y,1);
            else rorate(x,0);
            rorate(x,1);
        }
        else
        {
            if (ch[y][1]==x) rorate(y,0);
            else rorate(x,1);
            rorate(x,0); 
        }
    }
    if (!goal) root=x;
}
void insert(int x)
{
    if (!root) return void(root=x);
    int now=root;
    for (;;)
    {
        if (Node[x]if (!ch[now][0])
                {ch[now][0]=x;fa[x]=now;break;}
            else
                now=ch[now][0];
        else
            if (!ch[now][1])
                {ch[now][1]=x;fa[x]=now;break;}
            else
                now=ch[now][1];
    }
    splay(x,0);
}
int find(node x)
{
    int now=root;
    for (;now;)
    {
        if (Node[now]==x) return now;
        if (Node[now]1];
        else now=ch[now][0];
    }
}
void erase(node x)
{
    int ID=find(x);
    splay(ID,0);
    if (!ch[ID][0]&&!ch[ID][1]) root=0;
    else if (!ch[ID][1]) root=ch[ID][0],fa[root]=0;
    else if (!ch[ID][0]) root=ch[ID][1],fa[root]=0;
    else
    {
        int now=ch[ID][0];
        while (ch[now][1]) now=ch[now][1];
        splay(now,root);
        ch[now][1]=ch[ID][1];
        fa[ch[ID][1]]=now;
        root=now;
        fa[root]=0;
    }
}
node Pre(node x)
{
    int now=root;
    node ans=(node){0,0};
    for (;now;)
    {
        if (Node[now]if (!ans.id||ans1];
        }
        else
            now=ch[now][0];
    }
    return ans;
}
node Sub(node x)
{
    int now=root;
    node ans=(node){0,0};
    for (;now;)
    {
        if (xif (!ans.id||Node[now]0];
        }
        else
            now=ch[now][1];
    }
    return ans;
}
void init()
{
    for (int i=1;i<=m;++i)
        if (b[i].opt)
            c[++tot].data=b[i].x0,
            c[tot].id=i,
            c[tot].tp=2,
            c[++tot].data=b[i].x1,
            c[tot].id=i,
            c[tot].tp=3;
    Node[++cnt]=(node){1,n+1};
    insert(cnt);
    Node[++cnt]=(node){0,n+1};
    insert(cnt);
    sort(c+1,c+tot+1);
    for (int i=1;i<=tot;++i)
    {
        seg=c[i].data;
        node tmp,t1,t2;
        tmp=(node){c[i].tp,c[i].id};
        t1=Pre(tmp);
        t2=Sub(tmp);
        if (c[i].tp>=2)
        {
            int t;
            if (t1.id==t2.id) t=t1.id;
            else if (dep[t1.id]==dep[t2.id]) t=Fa[t1.id];
            else if (dep[t1.id]>dep[t2.id]) t=t2.id;
            else t=t1.id;
            if (c[i].tp==2) b[c[i].id].l=t;
            else b[c[i].id].r=t;
        }
        else if (c[i].tp)
        {

            if (t1.id==t2.id)
                dep[c[i].id]=dep[t1.id]+1,
                Fa[c[i].id]=t1.id;
            else if (dep[t1.id]==dep[t2.id])
                dep[c[i].id]=dep[t1.id],
                Fa[c[i].id]=Fa[t1.id];
            else if (dep[t1.id]>dep[t2.id])
                dep[c[i].id]=dep[t1.id],
                Fa[c[i].id]=t2.id;
            else
                dep[c[i].id]=dep[t2.id],
                Fa[c[i].id]=t1.id;
            add(c[i].id,Fa[c[i].id],a[c[i].id].val);
            Node[++cnt]=(node){1,c[i].id};
            insert(cnt);
            Node[++cnt]=(node){0,c[i].id};
            insert(cnt);
        }
        else
            erase((node){1,c[i].id}),
            erase((node){0,c[i].id});
    }
}
void dfs1(int x)
{
    siz[x]=1;
    for (int i=first[x];i;i=e[i].next)
        if (e[i].v!=fa[x])
            fa[e[i].v]=x,
            dep[e[i].v]=dep[x]+1,
            val[e[i].v]=e[i].w,
            dfs1(e[i].v),
            siz[x]+=siz[e[i].v],
            son[x]=(!son[x]||siz[son[x]].v]?e[i].v:son[x]);
}
void dfs2(int x,int tp)
{
    dfn[x]=++dfn[0];
    pre[dfn[0]]=x;
    top[x]=tp;
    if (son[x]) dfs2(son[x],tp);
    for (int i=first[x];i;i=e[i].next)
        if (son[x]!=e[i].v&&fa[x]!=e[i].v)
            dfs2(e[i].v,e[i].v);
}
void build(int rt,int begin,int end)
{
    if (begin==end) return void(tr[rt]=val[pre[end]]);
    int mid=begin+end>>1;
    build(rt<<1,begin,mid);
    build(rt<<1|1,mid+1,end);
    tr[rt]=tr[rt<<1]^tr[rt<<1|1];
}
void update(int rt,int begin,int end,int pos,int val)
{
    if (begin==end) return void(tr[rt]=val);
    int mid=begin+end>>1;
    if (mid>=pos) update(rt<<1,begin,mid,pos,val);
    else update(rt<<1|1,mid+1,end,pos,val);
    tr[rt]=tr[rt<<1]^tr[rt<<1|1];
}
int get(int rt,int begin,int end,int l,int r)
{
    if (l<=begin&&end<=r) return tr[rt];
    int mid=begin+end>>1,ans=0;
    if (mid>=l) ans^=get(rt<<1,begin,mid,l,r);
    if (mid1|1,mid+1,end,l,r);
    return ans;
}
main()
{ 
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i)
        if (in()=='P')
        {
            a[i].tp=0;
            scanf("%d",&a[i].L);
            double xx,yy;int mi=-1,mx=-1;
            for (int j=0;j.L;++j)
                scanf("%lf%lf",&xx,&yy),
                tmp[j]=make_pair(xx,yy),
                mi=(mi==-1||tmp[mi].first>xx?j:mi),
                mx=(mx==-1||tmp[mx].firstfor (int j=mi;j!=mx;j=(j+1)%a[i].L)
                a[i].up.push_back(tmp[j]);
            a[i].up.push_back(tmp[mx]);
            for (int j=mx;j!=mi;j=(j+1)%a[i].L)
                a[i].down.push_back(tmp[j]);
            a[i].down.push_back(tmp[mi]);
            c[++tot].tp=1;c[tot].data=tmp[mi].first;c[tot].id=i;
            c[++tot].tp=0;c[tot].data=tmp[mx].first;c[tot].id=i;
            scanf("%d",&a[i].val);
        }
        else
            a[i].tp=1,
            scanf("%lf%lf%lf%d",&a[i].x,&a[i].y,&a[i].r,&a[i].val),
            c[++tot].tp=1,c[tot].data=a[i].x-a[i].r,c[tot].id=i,
            c[++tot].tp=0,c[tot].data=a[i].x+a[i].r,c[tot].id=i;
    for (int i=1;i<=m;++i)
        if (in()=='C')
            b[i].opt=0,
            scanf("%d%d",&b[i].l,&b[i].r);
        else
            b[i].opt=1,
            scanf("%lf%lf%lf%lf",&b[i].x0,&b[i].y0,&b[i].x1,&b[i].y1);
    init();
    ++n;
    dfs1(n);
    dfs2(n,n);
    build(1,1,n);
    int ans=0;
    for (int i=1;i<=m;++i)
        if (!b[i].opt)
            update(1,1,n,dfn[b[i].l],b[i].r);
        else
        {
            int x=b[i].l,y=b[i].r;
            for (;top[x]!=top[y];x=fa[top[x]])
            {
                if (dep[top[x]]1,1,n,dfn[top[x]],dfn[x]);
            }
            if (dep[x]>dep[y]) swap(x,y);
            if (x!=y) ans^=get(1,1,n,dfn[son[x]],dfn[y]);
            printf("%d\n",ans);
        }
}

你可能感兴趣的:(【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖)