[BZOJ2584][Wc2012]memory(扫描线+splay+线段树)

博客探讨了一道二维平面中的线段移动问题,其中线段不会相交。通过使用扫描线算法配合Splay树来维护线段在特定横坐标上的相对位置,构造合法的线段移动序列。同时,借助线段树解决查询线段移动范围内的最大和最小拓扑序,以判断移动合法性。博主分享了题目解析和代码实现,并提到在不同评测系统的不同结果。
摘要由CSDN通过智能技术生成

题目描述

传送门

题目大意:在二维平面中有n个线段,线段互不相交,每一次一个操作将一个线段向四个方向之一移走(也就是平移到无穷远处),如果移动的过程中被其他线段所阻挡则移动是不合法的。求:最早的一次不合法移动;构造一种合法的移动序列将所有线段移走

题解

首先考虑第二问,实际上所有的线段都按照任意一个固定的方向移动就是可以直接都移走的,所以我们需要将线段编号。因为线段均不相交,所以对于任意两条线段的所有横坐标x,它们所对应的纵坐标y的相对位置是不变的,所以可以用splay来维护。将线段拆成左端点和右端点,按照x坐标排序做扫描线,扫到线段的左端点就在splay中插入一个点,插入的过程中需要计算之前splay中的线段在横坐标为x时的纵坐标y来判断插入的位置。遇到线段的右端点就在splay中删除。每一次插入之后找一下这个点的前驱后继并且由前驱向这个点、由这个点向后继连边,这样连出来一个DAG,求拓扑序即为合法的删除序列。
在第二问的基础上考虑第一问,横竖做两遍扫描线可以求出来两个方向上的拓扑序。将线段的正序删除转化为倒序插入,每一次看这条线段是否能移动需要查询一下在这个方向上、这个线段范围内已经插入的线段的拓扑序的最大值和最小值,如果有空的才能向那个方向移动。每一次插入将这个线段所控制的区间更新一下,可以用线段树来实现。注意由于端点相交是合法的,所以离散化的时候需要在两个点之间都插入一个点。

可是这道题我用wc2012的官方数据评测都没有问题,交到bzoj上wa了,询问管理员得到了模棱两可的回复。。懒得管了。。

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
#define N 200005

struct Point
{
    int x,y;
    Point(int X=0,int Y=0)
    {
        x=X,y=Y;
    }
};
struct Segment
{
    Point a,b;
    Segment(Point A=Point(0,0),Point B=Point(0,0))
    {
        a=A,b=B;
    }
    void read(){
  scanf("%d%d%d%d",&a.x,&a.y,&b.x,&b.y);}
    void check(){
  if (a.x>b.x) swap(a.x,b.x),swap(a.y,b.y);}
    void Swap(){swap(a.x,a.y),swap(b.x,b.y);}
}line[N];
struct OPT {
  int x,id,ty;}opt[N<<1];
struct MOVE {
  int id,dir;}move[N];

int n,inf,Min,Max,LSH,lsh[N<<1],ans1,ans2[N];
int root,sz,f[N],ch[N][2],id_in_splay[N],id_in_graph[N];double K[N],B[N];
int tot,point[N],nxt[N<<1],v[N<<1],in[N],ver[N],hor[N];
int minn[N*20],maxn[N*20],deltamx[N*20],deltamn[N*20];
queue <int> q;

//---------------------------------------splay------------------------------------------
void splay_clear(int x)
{
    f[x]=ch[x][0]=ch[x][1]=id_in_graph[x]=0;
    K[x]=B[x]=0;
}
int get(int x)
{
    return ch[f[x]][1]==x;
}
void rotate(
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值