题目大意
给定 n n n 个矩形,每条边都平行与坐标轴的一条边,分别有 4 4 4 个量 x i , y i , L x i , L y i x_{i},y_{i},Lx_{i},Ly_{i} xi,yi,Lxi,Lyi , x i , y i x_{i},y_{i} xi,yi 表示矩形左下角的点的坐标, L x i , L y i Lx_{i},Ly_{i} Lxi,Lyi 表示在横纵坐标的长度,保证两两矩形不重合,每次给定操作的矩形,表示将该矩形向左移动直至碰到坐标轴或其他矩形的边,保证一个矩形不会操作 2 2 2 次或以上,最后输出每个矩形的操作后左下点的坐标。
Input & Output
输入
n
n
n 表示
n
n
n 个矩形。
之后输入
n
n
n 行
x
i
,
y
i
,
L
x
i
,
L
y
i
x_{i},y_{i},Lx_{i},Ly_{i}
xi,yi,Lxi,Lyi 。
最后输入
n
n
n 个数
a
a
a 表示移动第
i
i
i 个矩形。
输出
n
n
n 行表示第
i
i
i 行操作完后左下点坐标。
数据范围
0 ≤ x i , y i , L x i , L y i ≤ 2 31 − 1 , 0 ≤ n ≤ 1 0 5 0 \le x_{i},y_{i},Lx_{i},Ly_{i} \le 2^{31}-1,0 \le n \le 10^5 0≤xi,yi,Lxi,Lyi≤231−1,0≤n≤105 。
思路
因为矩形移动时所受到影响的矩形时可以确定范围的,所以我们考虑预处理出来每一个矩形所能到达的其他矩形。
考虑按照横坐标从小到大将矩形排序,因为前面被覆盖的矩形肯定是不能影响后面矩形的,所以我们以纵坐标(要先离散化)建一颗线段树,区间
[
L
,
R
]
[L,R]
[L,R] 表示被覆盖的数是什么,有很多方法处理,我是将
m
a
x
max
max 和
m
i
n
min
min 值存储起来,倘若区间的
m
a
x
max
max 值等于
m
i
n
min
min 值,则证明这个区间只有一种矩形覆盖掉,直接和当前矩形连一条边即可。
最后操作时枚举可到达的矩形求最右边的最大值即可。
AC代码
#include<cstring>
#include<iostream>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int ax,ay,bx,by,id;
}d[200200];
struct T{
int maxn,minn;
}tree[800800];
struct nod{
int head,to,nxt;
}edge[4000200];
struct zlz{
int val,id,k;
}yy[200200];
int n,cnt,lisan[200200],tag[800800],tot,a,to[200200];
void xx(int u,int v)
{
edge[cnt].to=v;
edge[cnt].nxt=edge[u].head;
edge[u].head=cnt;
cnt++;
}
void pushup(int k)
{
tree[k].maxn=max(tree[k*2].maxn,tree[k*2+1].maxn);
tree[k].minn=min(tree[k*2].minn,tree[k*2+1].minn);
return;
}
void pushdown(int k)
{
tree[k*2].maxn=tree[k*2].minn=tag[k];
tree[k*2+1].maxn=tree[k*2+1].minn=tag[k];
tag[k*2]=tag[k],tag[k*2+1]=tag[k];
tag[k]=0;
}
void query(int k,int l,int r,int L,int R,int id)
{
if(tree[k].maxn==0)
return;
if(tree[k].maxn==tree[k].minn&&L<=l&&r<=R)
{
// printf("!!!%d\n",tree[k].maxn);
xx(id,tree[k].maxn);
return;
}
int mid=(l+r)/2;
if(tag[k])
pushdown(k);
if(R<=mid)
query(k*2,l,mid,L,R,id);
else if(L>mid)
query(k*2+1,mid+1,r,L,R,id);
else
query(k*2,l,mid,L,mid,id),query(k*2+1,mid+1,r,mid+1,R,id);
}
void change(int k,int l,int r,int L,int R,int id)
{
if(L<=l&&r<=R)
{
tree[k].maxn=id,tree[k].minn=id;
tag[k]=id;
return;
}
int mid=(l+r)/2;
if(tag[k])
pushdown(k);
if(R<=mid)
change(k*2,l,mid,L,R,id);
else if(L>mid)
change(k*2+1,mid+1,r,L,R,id);
else
change(k*2,l,mid,L,mid,id),change(k*2+1,mid+1,r,mid+1,R,id);
pushup(k);
}
bool cmp(node x,node y)
{
return x.ax<y.ax;
}
bool cmp2(zlz x,zlz y)
{
return x.val<y.val;
}
int main()
{
memset(edge,-1,sizeof(edge));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d %d %d %d",&d[i].ax,&d[i].ay,&d[i].bx,&d[i].by),d[i].bx+=d[i].ax,d[i].by+=d[i].ay,d[i].id=i;
tot++,yy[tot].id=i,yy[tot].val=d[i].ay,yy[tot].k=0;
tot++,yy[tot].id=i,yy[tot].val=d[i].by,yy[tot].k=1;
}
sort(yy+1,yy+tot+1,cmp2);
int now=0;
for(int i=1;i<=tot;i++)
{
if(i==1||yy[i].val!=yy[i-1].val)
now++;
if(yy[i].k==0)
d[yy[i].id].ay=now;
else
d[yy[i].id].by=now;
}
sort(d+1,d+n+1,cmp);
for(int i=1;i<=n;i++)
{
to[d[i].id]=i;
// printf("%d\n",i);
query(1,1,tot,d[i].ay+1,d[i].by,i);
change(1,1,tot,d[i].ay+1,d[i].by,i);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&a);
a=to[a];
int maxn=0;
for(int j=edge[a].head;j!=-1;j=edge[j].nxt)
{
int y=edge[j].to;
maxn=max(maxn,d[y].bx);
}
int len=d[a].bx-d[a].ax;
d[a].ax=maxn,d[a].bx=d[a].ax+len;
}
for(int i=1;i<=n;i++)
printf("%d\n",d[to[i]].ax);
return 0;
}