推箱子

链接:

https://ac.nowcoder.com/acm/contest/176/B

来源:牛客网

题目描述

在平面上有\(n\)个箱子,每个箱子都可以看成一个矩形,两条边都和坐标轴平行。任何两个矩形都不相交,但可能有某个点或某条边重合。约定\(x\)轴正方向为右,\(y\)轴正方向为上。

现在\(\tt{Fizzydavid}\)要推这些箱子。他会选择某个箱子开始,并以每秒\(1\)个单位的速度使这个箱子向右移动。如果路上正面碰上某个箱子,被碰上的箱子会在碰到的那个瞬间开始进入运动状态,以\(1\)个单位的速度向右移动,不会转动或改变运动方向。

准确地说,在某个时刻一个箱子\(i\)处于移动状态当且仅当:\(i\)是选择的箱子,或者存在一个处于移动状态的箱子\(j\),它的右边界等于箱子\(i\)的左边界,且它们在\(y\)轴上的投影的公共长度\(>0\)。你可以发现在这种情况下,任意时刻每个矩形仍然不相交。

\(\tt{Fizzydavid}\)告诉了你所有的信息,需要你求出\(k\)秒后每个矩形的位置。

输入描述:

第一行两个整数\(n\),\(t\)和\(k\)。\(\tt{Fizzydavid}\)开始选择的是输入的第\(t\)个矩形。

接下来\(n\)行每行四个整数\(x_{1,i},y_{1,i},x_{2,i},y_{2,i}\),表示矩形的左下角坐标是\((x_{1,i},y_{1,i})\),右上角坐标是\((x_{2,i},y_{2,i})\)。

输出描述:

输出一行\(n\)个整数,第\(i\)个整数表示\(k秒\)后第\(i\)个矩形的左下角的\(x\)坐标。你可以发现只要知道这个值就能唯一确定矩形的位置。

说明

对于\(30\%\)的数据,\(k\le 100\)。

对于另外\(40\%\)的数据,\(n\le 1000\)。

对于所有的数据,\(n\le 10^5\),\(1\le t\le n\),\(1\le k\le 10^9\),所有坐标都在\(-10^9\)和\(10^9\)之间。保证任意两个矩形不相交。


据说正解是优化连边最短路算法?为什么不试试类似扫描线的算法呢?(考场上线段树数组开小爆\(70\)了

按照矩形的左边界\(x\)坐标为关键字进行排序,从最开始的那个矩形一个一个做过去。

具体的,对矩形在\(y\)轴方向的凸起用线段树维护,每次加入一个矩形的时候查询\(y\)上面区间的最大值,然后看能不能顶到\(\tt{Ta}\)

支持区间赋值和区间最大值就可以了,离散化和动态开点都可以。注意覆盖情况的小细节。


Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=2e5+10;
struct node
{
int s,t,l,r,id;
bool friend operator <(node n1,node n2){return n1.s<n2.s;}
}mat[N];
int y[N<<1],cnt,n,t,k;
int tag[N<<2],mx[N<<2],ans[N],Time[N];
#define ls id<<1
#define rs id<<1|1
int max(int x,int y){return x>y?x:y;}
void pushdown(int id)
{
if(~tag[id])
{
mx[ls]=mx[rs]=tag[ls]=tag[rs]=tag[id];
tag[id]=-1;
}
}
void change(int id,int L,int R,int l,int r,int d)
{
if(l==L&&r==R)
{
mx[id]=max(mx[id],d);
tag[id]=mx[id];
return;
}
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) change(ls,L,Mid,l,r,d);
else if(l>Mid) change(rs,Mid+1,R,l,r,d);
else change(ls,L,Mid,l,Mid,d),change(rs,Mid+1,R,Mid+1,r,d);
mx[id]=max(mx[ls],mx[rs]);
}
int query(int id,int L,int R,int l,int r)
{
if(l==L&&r==R) return mx[id];
pushdown(id);
int Mid=L+R>>1;
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return max(query(ls,L,Mid,l,Mid),query(rs,Mid+1,R,Mid+1,r));
}
int main()
{
memset(tag,-1,sizeof(tag));
memset(mx,-1,sizeof(mx));
scanf("%d%d%d",&n,&t,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&mat[i].s,&mat[i].l,&mat[i].t,&mat[i].r);
--mat[i].r;
y[++cnt]=mat[i].r,y[++cnt]=mat[i].l,mat[i].id=i;
}
std::sort(y+1,y+1+cnt);
cnt=std::unique(y+1,y+1+cnt)-y-1;
for(int i=1;i<=n;i++)
{
mat[i].l=std::lower_bound(y+1,y+1+cnt,mat[i].l)-y;
mat[i].r=std::lower_bound(y+1,y+1+cnt,mat[i].r)-y;
}
std::sort(mat+1,mat+1+n);
for(int i=1;i<=n;i++) if(t==mat[i].id) {t=i;break;}
int d=mat[t].s;
change(1,1,cnt,mat[t].l,mat[t].r,mat[t].t-d);
Time[t]=k;
for(int i=t+1;i<=n;i++)
{
int dis=query(1,1,cnt,mat[i].l,mat[i].r);
if(dis==-1) continue;
if(k>=mat[i].s-(dis+d))
{
k-=mat[i].s-(dis+d);
d+=mat[i].s-(dis+d);
change(1,1,cnt,mat[i].l,mat[i].r,mat[i].t-d);
Time[i]=k;
}
else
break;
}
for(int i=1;i<=n;i++)
ans[mat[i].id]=mat[i].s+Time[i];
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}

2018.11.4

牛客网 提高组第8周 T2 推箱子 解题报告的更多相关文章

  1. 牛客网 提高组第8周 T1 染色

    染色 链接: https://ac.nowcoder.com/acm/contest/176/A 来源:牛客网 题目描述 \(\tt{fizzydavid}\)和\(\tt{leo}\)有\(n\)个 ...

  2. 18/9/16牛客网提高组Day2

    牛客网提高组Day2 T1 方差 第一眼看就知道要打暴力啊,然而并没有想到去化简式子... 可能因为昨晚没睡好,今天上午困死 导致暴力打了一个半小时,还不对... #include <algor ...

  3. 18/9/9牛客网提高组Day1

    牛客网提高组Day1 T1 中位数 这好像是主席树??听说过,不会啊... 最后只打了个暴力,可能是n2logn? 只过了前30%  qwq #include<algorithm> #in ...

  4. nowcoder(牛客网)提高组模拟赛第四场 解题报告

    T1 动态点分治 就是模拟..... 但是没有过!! 看了题解之后发现.... 坑点:有可能 \(x<=r\),但是

  5. 牛客网提高组模拟赛第七场 T3 洞穴(附bitset介绍)

    就是DP. 我们可以很简单的想到要枚举中间点,进行边数的转移. 但是因为边长数据范围很大,所以我们考虑log的倍增. 状态设计为\(dp[i][j][k]\),为从节点\(i\)走\(2^k\)步能否 ...

  6. 牛客网提高组模拟赛第七场 T2 随机生成树

    其实看懂题就很水啦qwq,就是求\(1-N\)的约数啦. 暴力求的话时间复杂度是\(O(NlogN)\)的,其实正解是枚举每个数的倍数......这样的时间复杂度是\(\frac{N}{1}+\fra ...

  7. 牛客网提高组模拟赛第五场 T1同余方程(异或)(位运算)

    区间不好做,但是我们可以转化成前缀来做.转化为前缀之后之后就是二维前缀和. 但是我还是不怎么会做.所以只能去看吉老师的题解 (确定写的那么简单真的是题解???). 我们要求模一个数余0,就等于找它的倍 ...

  8. nowcoder(牛客网)提高组模拟赛第一场 解题报告

    T1 中位数(二分) 这个题是一个二分(听说是上周atcoder beginner contest的D题???) 我们可以开一个数组b存a,sort然后二分b进行check(从后往前直接遍历check ...

  9. 牛客网提高组第二场---solution

    T1 方差 根据题目要求将式子先写出来注意下面式子中的 $n$ 全部都是 $n-1$$$\begin{aligned}ans&=n^2\times \frac{1}{n}\times \sum ...

随机推荐

  1. Qt-QML-C++交互实现文件IO系统

    QMl是没有自己的文件IO控制的,这里如果我们需要对文件进行读写操作,那么就需要去C++或者JS完成交互,交互方式有多种,由于我还没有掌握,这里就不介绍具体的交互方式了.这里就简单说明一下我的实现过程 ...

  2. TPO-14 C2 Prepare for a career in journalism

    TPO-14 C2 Prepare for a career in journalism 第 1 段 1.Listen to a conversation between a student and ...

  3. JavaScript基本概念(1)-声明提升

    声明提升: function > var > other var提升的时候,只是声明提升,但是赋值还是会在原来的位置. Javascript Hoisting:In javascript, ...

  4. ES6 之 let / const

    本博文配合 阮一峰 <ES6 标准入门(第3版)>一书进行简要概述 ES6 中的 let 与 const. 历史遗留问题 由于 JS ES3语法中的 var 提升变量.没有块级作用域,因而 ...

  5. IMPI Python集群运行报错:

    Intel MPI环境利用hostfile多主机运行下报错 HYDU_process_mfile_token (../../utils/args/args.c:523): token slots no ...

  6. [c++] Getting Started - CMake

    CMake is an open-source cross platform build system, according to CMake's creator, Kitware. But CMak ...

  7. Bus of Characters(栈和队列)

    In the Bus of Characters there are nn rows of seat, each having 22 seats. The width of both seats in ...

  8. oracle数据库之游标的使用

    一.游标概念 为了处理 SQL 语句,ORACLE 必须分配一片叫上下文( context area )的区域来处理所必需的信息,其中包括要处理的行的数目,一个指向语句被分析以后的表示形式的指针以及查 ...

  9. android AndroidManifest.xml uses-feature 详解

    如果你是一个Android用户,而且你有一个老旧的安装有android 1.5 的android设备,你可 能会注意到一些高版本的应用没有在手机上的Android Market 中显示.这必定是应用使 ...

  10. Java中Collection和Collections的区别(转载)

    转载来源:http://www.cnblogs.com/dashi/p/3597937.html 1.java.util.Collection 是一个集合接口(集合类的一个顶级接口).它提供了对集合对 ...