BZOJ3718[PA2014]Parking——树状数组
题目描述
你的老板命令你将停车场里的车移动成他想要的样子。
停车场是一个长条矩形,宽度为w。我们以其左下角顶点为原点,坐标轴平行于矩形的边,建立直角坐标系。停车场很长,我们可以认为它一直向右边伸展到无穷远处。
车都是边平行于坐标轴的矩形,大小可能不同。你可以将车任意地平移(但不能旋转),只要他们不超出停车场的边界,且不能互相碰撞,但紧挨着是允许的(即任意时刻任两辆车的重叠面积为0)。
你知道目前各辆车的摆放位置,以及老板心中所想的位置。你需要判断是否可以办到老板的任务。
输入
第一行为一个整数t(1<=t<=20),表示测试数据数量。
对于每组测试数据,第一行两个整数n,w(1<=n<=50000,1<=w<=10^9),分别表示车的数量和停车场的宽度。
接下来n行,第i行有四个整数x1,y1,x2,y2(0<=x1,x2<=10^9,0<=y1,y2<=w),表示编号为i的车的当前位置是由x1,y1,x2,y2确定的矩形。(注意:数据有可能出现x1>x2或y1>y2)
再接下来n行,格式和意义同上,表示车的目标位置。
输出
输出t行,第i行为TAK(是)或NIE(否),表示第i组测试数据中能否按照要求进行移动。
样例输入
2
3 3
0 0 2 2
2 1 4 3
4 0 6 1
0 0 2 2
2 1 4 3
0 2 2 3
3 3
0 0 2 2
2 1 4 3
4 0 6 1
2 1 4 3
0 0 2 2
4 0 6 1
3 3
0 0 2 2
2 1 4 3
4 0 6 1
0 0 2 2
2 1 4 3
0 2 2 3
3 3
0 0 2 2
2 1 4 3
4 0 6 1
2 1 4 3
0 0 2 2
4 0 6 1
样例输出
TAK
NIE
NIE
发现如果一个车能停到目标位置那么只要这两个位置之间每辆车的宽度与这个车的宽度之和不大于w就行。
对于两辆车x,y如果他们当前的相对位置与目标相对位置不同(即当前是x,y,目标是y,x)那么这两个车的宽度之和就要<=w。
用树状数组维护宽度的前缀最大值每次查询前缀最大值和当前车宽度加和是否<=w即可。
#include<set> #include<map> #include<queue> #include<stack> #include<cmath> #include<cstdio> #include<vector> #include<bitset> #include<cstring> #include<iostream> #include<algorithm> using namespace std; struct miku { int a,b,c,d; int w; int id; }s1[50010],s2[50010]; int v[50010]; int n,m,T; int flag; int pos[50010]; bool cmp(miku a,miku b) { if(a.a!=b.a) { return a.a<b.a; } return a.c<b.c; } void add(int x,int val) { for(int i=x;i<=n;i+=i&-i) { v[i]=max(v[i],val); } } int ask(int x) { int res=0; for(int i=x;i;i-=i&-i) { res=max(res,v[i]); } return res; } int main() { scanf("%d",&T); while(T--) { flag=0; memset(v,0,sizeof(v)); memset(pos,0,sizeof(pos)); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&s1[i].a,&s1[i].b,&s1[i].c,&s1[i].d); if(s1[i].a>s1[i].c) { swap(s1[i].a,s1[i].c); } if(s1[i].b>s1[i].d) { swap(s1[i].b,s1[i].d); } s1[i].w=s1[i].d-s1[i].b; s1[i].id=i; } for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&s2[i].a,&s2[i].b,&s2[i].c,&s2[i].d); if(s2[i].a>s2[i].c) { swap(s2[i].a,s2[i].c); } if(s2[i].b>s2[i].d) { swap(s2[i].b,s2[i].d); } s2[i].w=s2[i].d-s2[i].b; s2[i].id=i; } sort(s1+1,s1+1+n,cmp); sort(s2+1,s2+1+n,cmp); for(int i=1;i<=n;i++) { pos[s1[i].id]=i; } for(int i=n;i>=1;i--) { if(flag==1) { break; } if(ask(pos[s2[i].id])+s2[i].w>m) { flag=1; } add(pos[s2[i].id],s2[i].w); } printf(flag==1?"NIE\n":"TAK\n"); } }