当前位置: 首页 > news >正文

BZOJ 2584: [Wc2012]memory(扫描线+线段树)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2584

题意:给出平面n个线段,任意两个线段严格不相交,且每个线段不平行于坐标轴。移走所有线段。每次移走一个线段,移n次,移走时只能竖直向下、向上或水平向左向右移走。每次移动时不能与当前还有的其他线段相交(顶点与顶点相交允许)。要求解决两个问题:

(1)题目给出了一种移走的序列,但是这个序列是不合法的。找出这个序列中最早的不合法的移动是第几个;

(2)要求你给出一种合法的移动序列。

 

思路:首先,我们来解决第二个问题。我们发现,只向一个方向移动是可以找到一个解的,这其实是一个拓扑图,我们的目标就是确定这个拓扑关系。比如竖直向上移动。我们可以用扫描线+set维护的方法来解决。

对于第一个问题,我们可以把移走的过程倒着进行,变为添加的过程。假如我们找到了竖直向上移走的拓扑关系。那么对于一个移走时是向上的线段,添加时是从上向下添加的,只要当前已经添加的所有里面的线段在拓扑图上都不是当前要添加的线段的前驱,当前添加就是合法的。其他的添加类似。

因此,我们可以为拓扑图重新标号,然后用线段树维护区间最大最小值即可。

 

const int INF=1000000007;
const int N=100005;

int a[N][4],b[N][2];
int n;

int e[2][N][2],Max[2];

vector<int> g[2][N];
int mp[2][N];

int c[N*2],cNum;

int curX;

struct node
{
    int id;
    double k,b;
    int x,flag;

    int operator<(const node &p) const
    {
        double xMin=k*curX+b;
        double pxMin=p.k*curX+p.b;
        return xMin>pxMin;
    }

    int operator==(const node &p) const
    {
        return id==p.id;
    }

};

node f[N*2];
int fNum;

int cmp(node a,node b)
{
    if(a.x!=b.x) return a.x<b.x;
    return a.flag>b.flag;
}

set<node> S;

int ind[N];

void cal(int t)
{
    cNum=0;
    for(int i=1;i<=n;i++)
    {
        c[++cNum]=a[i][0]+1;
        c[++cNum]=a[i][2];
    }
    sort(c+1,c+cNum+1);
    cNum=unique(c+1,c+cNum+1)-(c+1);

    Max[t]=cNum;

    fNum=0;
    for(int i=1;i<=n;i++)
    {
        fNum++;
        f[fNum].id=i;
        f[fNum].k=1.0*(a[i][3]-a[i][1])/(a[i][2]-a[i][0]);
        f[fNum].b=a[i][1]-f[fNum].k*a[i][0];
        f[fNum].x=lower_bound(c+1,c+cNum+1,a[i][0]+1)-c;
        f[fNum].flag=1;

        e[t][i][0]=f[fNum].x;


        fNum++;
        f[fNum].id=i;
        f[fNum].k=1.0*(a[i][3]-a[i][1])/(a[i][2]-a[i][0]);
        f[fNum].b=a[i][1]-f[fNum].k*a[i][0];
        f[fNum].x=lower_bound(c+1,c+cNum+1,a[i][2])-c;
        f[fNum].flag=-1;

        e[t][i][1]=f[fNum].x;
    }

    sort(f+1,f+fNum+1,cmp);

    S.clear();
    set<node>::iterator it;
    int cur=1;
    clr(ind,0);
    for(int i=1;i<=cNum;i++)
    {
        curX=c[i];
        while(cur<=fNum&&f[cur].x==i)
        {
            if(1==f[cur].flag)
            {
                S.insert(f[cur]);
                it=S.find(f[cur]);
                if(it!=S.begin())
                {
                    it--;
                    g[t][it->id].pb(f[cur].id);
                    ind[f[cur].id]++;
                }
                it=S.find(f[cur]);
                it++;
                if(it!=S.end())
                {
                    g[t][f[cur].id].pb(it->id);
                    ind[it->id]++;
                }
            }
            else S.erase(f[cur]);

            cur++;
        }
    }

    queue<int> Q;
    int curId=0;
    for(int i=1;i<=n;i++)
    {
        if(!ind[i]) Q.push(i),mp[t][i]=++curId;
    }
    while(!Q.empty())
    {
        int u=Q.front();
        Q.pop();

        for(int i=0;i<SZ(g[t][u]);i++)
        {
            int v=g[t][u][i];
            if(0==--ind[v]) Q.push(v),mp[t][v]=++curId;
        }
    }
}


struct SegNode
{
    int L,R,Min,Max;
    int detMin,detMax;

    void add(int x)
    {
        if(x<Min) Min=x;
        if(x>Max) Max=x;
        if(x<detMin) detMin=x;
        if(x>detMax) detMax=x;
    }
};

struct SegTree
{
    SegNode A[N*8];

    void build(int t,int L,int R)
    {
        A[t].L=L;
        A[t].R=R;
        A[t].Max=-INF;
        A[t].Min=INF;
        A[t].detMax=-INF;
        A[t].detMin=INF;
        if(L==R) return;
        int M=(L+R)>>1;
        build(t<<1,L,M);
        build(t<<1|1,M+1,R);
    }

    void pushDown(int t)
    {
        if(A[t].L==A[t].R) return;
        if(A[t].detMax!=-INF)
        {
            A[t<<1].add(A[t].detMax);
            A[t<<1|1].add(A[t].detMax);
            A[t].detMax=-INF;
        }
        if(A[t].detMin!=INF)
        {
            A[t<<1].add(A[t].detMin);
            A[t<<1|1].add(A[t].detMin);
            A[t].detMin=INF;
        }
    }

    void pushUp(int t)
    {
        A[t].Min=min(A[t<<1].Min,A[t<<1|1].Min);
        A[t].Max=max(A[t<<1].Max,A[t<<1|1].Max);
    }

    void add(int t,int L,int R,int x)
    {
        if(A[t].L==L&&A[t].R==R)
        {
            A[t].add(x);
            return;
        }
        pushDown(t);
        int M=(A[t].L+A[t].R)>>1;
        if(R<=M) add(t<<1,L,R,x);
        else if(L>M) add(t<<1|1,L,R,x);
        else
        {
            add(t<<1,L,M,x);
            add(t<<1|1,M+1,R,x);
        }
        pushUp(t);
    }

    pair<int,int> get(int t,int L,int R)
    {
        if(A[t].L==L&&A[t].R==R) return MP(A[t].Min,A[t].Max);
        pushDown(t);
        int M=(A[t].L+A[t].R)>>1;
        if(R<=M) return get(t<<1,L,R);
        if(L>M) return get(t<<1|1,L,R);
        pair<int,int> aa=get(t<<1,L,M);
        pair<int,int> bb=get(t<<1|1,M+1,R);
        if(bb.first<aa.first) aa.first=bb.first;
        if(bb.second>aa.second) aa.second=bb.second;
        return aa;
    }

}A[2];

int get()
{
    A[0].build(1,1,Max[0]);
    A[1].build(1,1,Max[1]);
    int ans=-1;
    for(int i=n;i>=1;i--)
    {
        int t=b[i][0];
        int d=b[i][1];
        if(0==d||2==d)
        {
            int L=e[1][t][0];
            int R=e[1][t][1];
            pair<int,int> p=A[1].get(1,L,R);
            if(0==d&&p.second>mp[1][t]||2==d&&p.first<mp[1][t]) ans=i;

        }
        else
        {
            int L=e[0][t][0];
            int R=e[0][t][1];
            pair<int,int> p=A[0].get(1,L,R);
            if(3==d&&p.second>mp[0][t]||1==d&&p.first<mp[0][t]) ans=i;

        }
        A[0].add(1,e[0][t][0],e[0][t][1],mp[0][t]);
        A[1].add(1,e[1][t][0],e[1][t][1],mp[1][t]);
    }
    return ans;
}

int h[N];

int main()
{

    n=myInt();
    for(int i=1;i<=n;i++)
    {
        a[i][0]=myInt();
        a[i][1]=myInt();
        a[i][2]=myInt();
        a[i][3]=myInt();
    }
    for(int i=1;i<=n;i++)
    {
        b[i][0]=myInt();
        b[i][1]=myInt();
    }

    for(int i=1;i<=n;i++) if(a[i][0]>a[i][2])
    {
        swap(a[i][0],a[i][2]);
        swap(a[i][1],a[i][3]);
    }
    cal(0);
    for(int i=1;i<=n;i++)
    {
        swap(a[i][0],a[i][1]);
        swap(a[i][2],a[i][3]);
    }
    for(int i=1;i<=n;i++) if(a[i][0]>a[i][2])
    {
        swap(a[i][0],a[i][2]);
        swap(a[i][1],a[i][3]);
    }
    cal(1);


    int ans=get();
    printf("%d\n",ans);
    for(int i=1;i<=n;i++) h[mp[0][i]]=i;
    for(int i=1;i<=n;i++) printf("%d 1\n",h[i]);
}

  

相关文章:

  • 用最新NLP库Flair做文本分类
  • ASP.NET Core 2.0 : 三. 项目结构
  • 前后端分离架构中接口测试最佳实践
  • js闭包与高阶函数
  • java知识点1(this指针)
  • Confluent 修改开源许可证,限制云供应商滥用
  • vagrant设置虚拟机的名字
  • 寒假作业安排及注意点
  • 团队管理 - 团队发展五阶段
  • 线性代数---范数
  • Delphi 调用C#编写的WebService 参数为Null解决方法
  • BZOJ 1449 球队收益(最小费用最大流)
  • PHP学习笔记2
  • (原創) 未来三学期想要修的课 (日記)
  • 【转载】一个Sqrt函数引发的血案
  • __proto__ 和 prototype的关系
  • ES6 ...操作符
  • JavaScript DOM 10 - 滚动
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • JSONP原理
  • scrapy学习之路4(itemloder的使用)
  • vue.js框架原理浅析
  • 理清楚Vue的结构
  • 配置 PM2 实现代码自动发布
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 通过几道题目学习二叉搜索树
  • 我从编程教室毕业
  • 线性表及其算法(java实现)
  • 新手搭建网站的主要流程
  • 学习笔记:对象,原型和继承(1)
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 用quicker-worker.js轻松跑一个大数据遍历
  • python最赚钱的4个方向,你最心动的是哪个?
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • ​一文看懂数据清洗:缺失值、异常值和重复值的处理
  • ​用户画像从0到100的构建思路
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #QT(串口助手-界面)
  • (Matalb时序预测)PSO-BP粒子群算法优化BP神经网络的多维时序回归预测
  • (附源码)springboot 校园学生兼职系统 毕业设计 742122
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (十六)一篇文章学会Java的常用API
  • (四)linux文件内容查看
  • (一)Neo4j下载安装以及初次使用
  • (源码版)2024美国大学生数学建模E题财产保险的可持续模型详解思路+具体代码季节性时序预测SARIMA天气预测建模
  • (转)Sql Server 保留几位小数的两种做法
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .net知识和学习方法系列(二十一)CLR-枚举
  • .NET中使用Redis (二)
  • @RequestBody的使用
  • @Valid和@NotNull字段校验使用
  • [ 渗透工具篇 ] 一篇文章让你掌握神奇的shuize -- 信息收集自动化工具
  • [AIGC] Spring Interceptor 拦截器详解
  • [AIGC] 开源流程引擎哪个好,如何选型?