您的位置:首页 > 其它

【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)H】【迭代 排序 模拟】Hilbert Sort 图形拐拐划分,经过所有点的

2015-12-03 09:20 686 查看


#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=2e5+10,M=0,Z=1e9+7,ms63=1061109567;
int casenum,casei;
int n;double S;
char s
[48];
struct A
{
int x,y,p,o;
bool operator < (const A& b)const{return o<b.o;}
}a
;
bool belong(double val,double bot,double top)
{
if(bot>top)swap(bot,top);
return val>=bot&&val<=top;
}
void solve(int l,int r,double x1,double y1,double x2,double y2,double x3,double y3,double x4,double y4)
{
double xmid=(x1+x3)/2;
double ymid=(y1+y3)/2;

double x11=(x1+x2)/2;
double y11=(y1+y2)/2;

double x22=(x2+x3)/2;
double y22=(y2+y3)/2;

double x33=(x3+x4)/2;
double y33=(y3+y4)/2;

double x44=(x4+x1)/2;
double y44=(y4+y1)/2;

for(int i=l;i<=r;++i)
{
if(belong(a[i].x,x1,xmid)&&belong(a[i].y,y1,ymid))a[i].o=1;
else if(belong(a[i].x,x2,xmid)&&belong(a[i].y,y2,ymid))a[i].o=2;
else if(belong(a[i].x,x3,xmid)&&belong(a[i].y,y3,ymid))a[i].o=3;
else if(belong(a[i].x,x4,xmid)&&belong(a[i].y,y4,ymid))a[i].o=4;
}
sort(a+l,a+r+1);

int ll=l,rr=l;
while(rr<=r&&a[rr].o==1)++rr;
if(ll<rr-1)solve(ll,rr-1,x1,y1,x44,y44,xmid,ymid,x11,y11);

ll=rr;while(rr<=r&&a[rr].o==2)++rr;
if(ll<rr-1)solve(ll,rr-1,x11,y11,x2,y2,x22,y22,xmid,ymid);

ll=rr;while(rr<=r&&a[rr].o==3)++rr;
if(ll<rr-1)solve(ll,rr-1,xmid,ymid,x22,y22,x3,y3,x33,y33);

ll=rr;while(rr<=r&&a[rr].o==4)++rr;
if(ll<rr-1)solve(ll,rr-1,x33,y33,xmid,ymid,x44,y44,x4,y4);
}
int main()
{
while(~scanf("%d%lf",&n,&S))
{
for(int i=1;i<=n;++i)
{
scanf("%d%d%s",&a[i].x,&a[i].y,s[i]);
a[i].p=i;
}
solve(1,n,0,0,0,S,S,S,S,0);
for(int i=1;i<=n;++i)puts(s[a[i].p]);
}
}
/*
【trick&&吐槽】
这题只是题意难读一点。
我们只要清晰地划分范围,多加上一些点做我们路径的限制条件,这道题的AC就变得简单啦!

【题意】 http://codeforces.com/gym/100820/attachments 给你一个S*S的平面,点的坐标范围是[0,S],我们要从[0,0]走到[S,0],具体的路径是——
[0,0]->[0,S]->[S,S]->[S,0],然后对于每一块,我们会按照类似的原则,迭代行进。
具可以参考题目给出的图片,细节上是——
以下面这个为一个基础图形,朝向认定为向上。
----
| |
| |
一旦发生迭代,就将会变成——
上 上
右 左

这个迭代给出的S是奇数,这样不停地迭代,每个整点最后都必然只会走过一次。
现在给你若干个点,让你求出这些点从[0,0]出发,到[S,0]的最终顺序。

【类型】
特殊规则的排序 迭代模拟

【分析】
显然,我们对于一个基准的图形,点的顺序是确定的。
对于一个基准的图形,所能分出的图形也是确定的。
我们已经有了迭代这个武器,只需要处理一个基础图形的分配即可。

具体实现怎么完成呢?
----
| |
| |
我们找到所有的关键点。
2 22 3
11 mid 33
1 44 4
我们这样迭代下去——
1->44->mid->11
11->2->22->mid
mid->22->3->>33
33->mid->44->4
把四个块的点划分为1,2,3,4.
并按照这个顺序排序。迭代到最后,就可以AC啦!

【时间复杂度&&优化】
O(n * logn(层数) *logn(每层的内部排序时间)

【数据】
14 25
5 5 Honolulu
5 10 PugetSound
5 20 Victoria
10 5 Berkeley
10 10 Portland
10 15 Seattle
10 20 Vancouver
15 5 LasVegas
15 10 Sacramento
15 15 Kelowna
15 20 PrinceGeorge
20 5 Phoenix
20 10 SaltLakeCity
20 20 Calgary

5 25
0 0 a
25 0 d
24 0 e
0 25 b
25 25 c
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息