BZOJ2934 : [Poi1999]祭坛问题

对于每个祭坛,算出每条线段阻碍它的角度区间,然后排序求并看看是否有空位即可,时间复杂度$O(n^2\log n)$。

这题在Main上官方时限是0.2S,因此需要几个常数优化:

$1.$为了避免用atan2(y,x)算角度,改成算斜率,所以需要分$4$个方向讨论。

$2.$对区间排序时,不要直接对结构体排序,而是对其指针排序。

$3.$在计算某个祭坛时,除了它本身需要特别计算之外,其它祭坛可以直接看成没有缺口的矩形,可以减少$n$个事件。

$4.$在计算的过程中,不断收缩左右边界,当左右边界重合时即可直接判定为不可能。

#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1005,BUF=50000;
const double eps=1e-9,inf=1e9;
int n,m,cnt,i,X,k,ce,flag;char dir[N],Buf[BUF],*buf=Buf;double L,R;
inline void read(int&a){for(a=0;*buf<48;buf++);while(*buf>47)a=a*10+*buf++-48;}
inline void read(char&a){while(*buf<‘A‘)buf++;a=*buf++;}
struct P{int x,y;P(){}P(int _x,int _y){x=_x,y=_y;}}a[N];
struct seg{
  P x,y;
  seg(){}
  seg(P _x,P _y){
    x=_x,y=_y;
    if(x.x>y.x||x.y>y.y)swap(x,y);
  }
}b[N*5],c[N*4],f[N];
struct E{
  double l,r;
  void set(double _l,double _r){
    l=_l,r=_r;
    if(l<L+eps)L=max(L,r);
    if(r>R-eps)R=min(R,l);
    if(L+eps>R)k=1;
  }
}e[N*4],*q[N*4];
inline bool cmp(E*x,E*y){return x->l<y->l;}
inline bool cal(int x,int y,double&t){
  if(x<=0)return 0;
  t=1.0*y/x;
  return 1;
}
inline double fix(double x){return x>0?inf:-inf;}
void initS(int x,int y){
  cal(-f[X].x.y+y,f[X].x.x-x,L);
  cal(-f[X].y.y+y,f[X].y.x-x,R);
  if(L>R)swap(L,R);
  for(int i=1;i<=m;i++)if((i+4)/5==X){
    seg&j=b[i];double l,r;
    if(!cal(-j.x.y+y,j.x.x-x,l))continue;
    if(!cal(-j.y.y+y,j.y.x-x,r))r=fix(l);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
  for(int i=1;i<=cnt&&!k;i++)if((i+3)/4!=X){
    seg&j=c[i];double l,r;
    if(!cal(-j.x.y+y,j.x.x-x,l))continue;
    if(!cal(-j.y.y+y,j.y.x-x,r))r=fix(l);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
}
void initN(int x,int y){
  cal(f[X].y.y-y,f[X].y.x-x,L);
  cal(f[X].x.y-y,f[X].x.x-x,R);
  if(L>R)swap(L,R);
  for(int i=1;i<=m;i++)if((i+4)/5==X){
    seg&j=b[i];double l,r;
    if(!cal(j.y.y-y,j.y.x-x,r))continue;
    if(!cal(j.x.y-y,j.x.x-x,l))l=fix(r);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
  for(int i=1;i<=cnt&&!k;i++)if((i+3)/4!=X){
    seg&j=c[i];double l,r;
    if(!cal(j.y.y-y,j.y.x-x,r))continue;
    if(!cal(j.x.y-y,j.x.x-x,l))l=fix(r);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
}
void initW(int x,int y){
  cal(-f[X].x.x+x,f[X].x.y-y,L);
  cal(-f[X].y.x+x,f[X].y.y-y,R);
  if(L>R)swap(L,R);
  for(int i=1;i<=m;i++)if((i+4)/5==X){
    seg&j=b[i];double l,r;
    if(!cal(-j.x.x+x,j.x.y-y,l))continue;
    if(!cal(-j.y.x+x,j.y.y-y,r))r=fix(l);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
  for(int i=1;i<=cnt&&!k;i++)if((i+3)/4!=X){
    seg&j=c[i];double l,r;
    if(!cal(-j.x.x+x,j.x.y-y,l))continue;
    if(!cal(-j.y.x+x,j.y.y-y,r))r=fix(l);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
}
void initE(int x,int y){
  cal(f[X].y.x-x,f[X].y.y-y,L);
  cal(f[X].x.x-x,f[X].x.y-y,R);
  if(L>R)swap(L,R);
  for(int i=1;i<=m;i++)if((i+4)/5==X){
    seg&j=b[i];double l,r;
    if(!cal(j.y.x-x,j.y.y-y,r))continue;
    if(!cal(j.x.x-x,j.x.y-y,l))l=fix(r);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
  for(int i=1;i<=cnt&&!k;i++)if((i+3)/4!=X){
    seg&j=c[i];double l,r;
    if(!cal(j.y.x-x,j.y.y-y,r))continue;
    if(!cal(j.x.x-x,j.x.y-y,l))l=fix(r);
    if(l>r)swap(l,r);
    if(r<L-eps||l>R+eps)continue;
    e[ce++].set(l,r);
  }
}
bool check(){
  if(k)return 0;
  for(int i=0;i<ce;i++)q[i]=e+i;
  sort(q,q+ce,cmp);
  for(int i=0;i<ce;i++){
    if(q[i]->l>L+eps)return 1;
    if(L<q[i]->r)L=q[i]->r;
  }
  return 0;
}
int main(){
  fread(Buf,1,BUF,stdin);read(n);
  for(i=1;i<=n;i++){
    int x1,y1,x2,y2,o;char d;
    read(x1),read(y1),read(x2),read(y2),read(d);
    x1<<=2,y1<<=2,x2<<=2,y2<<=2;
    if(x1>x2)swap(x1,x2);
    if(y1>y2)swap(y1,y2);
    a[i]=P((x1+x2)/2,(y1+y2)/2);
    dir[i]=d;
    if(d!=‘S‘)b[++m]=seg(P(x1,y1),P(x2,y1));
    else{
      o=(x1+x2)/2;
      b[++m]=seg(P(x1,y1),P((x1+o)/2,y1));
      b[++m]=seg(P(x2,y1),P((x2+o)/2,y1));
      f[i]=seg(P((x1+o)/2,y1),P((x2+o)/2,y1));
    }
    if(d!=‘N‘)b[++m]=seg(P(x1,y2),P(x2,y2));
    else{
      o=(x1+x2)/2;
      b[++m]=seg(P(x1,y2),P((x1+o)/2,y2));
      b[++m]=seg(P(x2,y2),P((x2+o)/2,y2));
      f[i]=seg(P((x1+o)/2,y2),P((x2+o)/2,y2));
    }
    if(d!=‘W‘)b[++m]=seg(P(x1,y1),P(x1,y2));
    else{
      o=(y1+y2)/2;
      b[++m]=seg(P(x1,y1),P(x1,(y1+o)/2));
      b[++m]=seg(P(x1,y2),P(x1,(y2+o)/2));
      f[i]=seg(P(x1,(y1+o)/2),P(x1,(y2+o)/2));
    }
    if(d!=‘E‘)b[++m]=seg(P(x2,y1),P(x2,y2));
    else{
      o=(y1+y2)/2;
      b[++m]=seg(P(x2,y1),P(x2,(y1+o)/2));
      b[++m]=seg(P(x2,y2),P(x2,(y2+o)/2));
      f[i]=seg(P(x2,(y1+o)/2),P(x2,(y2+o)/2));
    }
    c[++cnt]=seg(P(x1,y1),P(x2,y1));
    c[++cnt]=seg(P(x1,y2),P(x2,y2));
    c[++cnt]=seg(P(x1,y1),P(x1,y2));
    c[++cnt]=seg(P(x2,y1),P(x2,y2));
  }
  for(X=1;X<=n;X++){
    ce=k=0;
    if(dir[X]==‘S‘)initS(a[X].x,a[X].y);
    if(dir[X]==‘N‘)initN(a[X].x,a[X].y);
    if(dir[X]==‘W‘)initW(a[X].x,a[X].y);
    if(dir[X]==‘E‘)initE(a[X].x,a[X].y);
    if(check())flag=1,printf("%d\n",X);
  }
  if(!flag)puts("BRAK");
  return 0;
}

  

时间: 2024-10-18 04:34:30

BZOJ2934 : [Poi1999]祭坛问题的相关文章

BZOJ 2929: [Poi1999]洞穴攀行

2929: [Poi1999]洞穴攀行 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 351  Solved: 195[Submit][Status][Discuss] Description 洞穴学者在Byte Mountain的Grate Cave里组织了一次训练.训练中,每一位洞穴学者要从最高的一个室到达最底下的一个室.他们只能向下走.一条路上每一个连续的室都要比它的前一个低.此外,每一个洞穴学者都要从最高的室出发,沿不同的路走到最低的室.

2929: [Poi1999]洞穴攀行

2929: [Poi1999]洞穴攀行 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 80  Solved: 41[Submit][Status][Discuss] Description 一队洞穴学者在Byte Mountain的Grate Cave里组织了一次训练.训练中,每一位洞穴学者要从最高的一个室到达最底下的一个室.他们只能向下走.一条路上每一个连续的室都要比它的前一个低.此外,每一个洞穴学者都要从最高的室出发,沿不同的路走到最低的室.问

luogu 3415 祭坛

题目大意: Dgeak大陆可以看成一个用平面直角坐标系表示的巨大平面.在这个平面上,有 n 个Swaryea水晶柱,每个水晶柱可以用一个点表示. 如果 4 个水晶柱依次相连可以构成一个四边形,满足其两条对角线分别平行于 x 轴和 y 轴,并且对角线的交点位于四边形内部(不包括边界),那么这 4 个水晶柱就可以建立一个结界.其中,对角线的交点称作这个结界的中心. 例如下左图中,水晶柱 ABCD 可以建立一个结界,其中心为 O.   为了起到抵御Dar-dzo-nye的最佳效果,人们会把祭坛修建在最

luoguP3415 祭坛

https://www.luogu.org/problemnew/show/P3415 考虑二分结界层数,将 n 个点按 x 大小依次加入答案,一行一行的做,用树状数组维护当前这一行中[0, x - 1] 包含祭坛大于 mid 的且 [x + 1, n] 中包含的祭坛也大于 mid 的坐标,再计算出这一行有几个地方可以作为中心,简单容斥(可能还不算容斥?)一下就可以了 有一个坑就是当节点层数是 0 的时候输出两行 0 #include <bits/stdc++.h> using namespa

【bzoj2935】【Poi1999】原始生物

2935: [Poi1999]原始生物 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 145  Solved: 71[Submit][Status][Discuss] Description 原始生物的遗传密码是一个自然数的序列K=(a1,...,an).原始生物的特征是指在遗传密码中连续出现的数对(l,r),即存在自然数i使得l=ai且r=ai+1.在原始生物的遗传密码中不存在(p,p)形式的特征. 求解任务: 请设计一个程序: ·读入一系列的特

人皇尺就喺祭坛之中,你哋若是睇到形似祭坛嘅嘢就立

人皇大殿漆黑匹,内中唔知有几年冇入过光线,充斥住一铺霉味,阴冷潮湿,其中重有一种古怪嘅刺鼻瀡.喺呢度,即便系修士嘅目光都睇唔见远处,鼆到纯粹匹.蓝烨早有准备从怀中拎出一盏油灯嚟,呢油灯睇落同普通嘅油灯冇咩有咩唔同,蓝烨汇入修为,油灯灯捻就畀点燃,连随一粒火球由油灯上冉冉升起,悬喺蓝烨头顶,将周围嘅一切全部照亮. http://www.dianyuan.com/people/782099 面嘅时候,心中齐齐一紧.呢度,遍地都系干尸骸骨.呢度好似曾经发生咗一场大,呢啲干尸骸骨们仲保留住死前嘅状态,佢

CCF 201609-5 祭坛

问题描述 试题编号: 201609-5 试题名称: 祭坛 时间限制: 2.0s 内存限制: 256.0MB 问题描述: 问题描述 在遥远的Dgeak大陆,生活着一种叫做Dar-dzo-nye的怪物.每当这种怪物降临,人们必须整夜对抗怪物而不能安睡.为了乞求这种怪物不再降临,人们决定建造祭坛. Dgeak大陆可以看成一个用平面直角坐标系表示的巨大平面.在这个平面上,有 n 个Swaryea水晶柱,每个水晶柱可以用一个点表示. 如果 4 个水晶柱依次相连可以构成一个四边形,满足其两条对角线分别平行于

BZOJ2929 [Poi1999]洞穴攀行

我说这题怎么看着觉得怪怪的... PoPoQQQ给出了解答:"给定一个有向图,与起点和终点相连的边只能走一次,剩下的边可以走无数次,问起点到终点可以走多少个人" 题目翻译错了233 好了,那不就是裸的网络流了吗? 1 /************************************************************** 2 Problem: 2929 3 User: rausen 4 Language: C++ 5 Result: Accepted 6 Time

BZOJ 2927 POI1999 多边形之战 博弈论

题目大意:给定一个凸多边形的三角剖分,其中一个三角形被涂成了黑色,每次可以割一刀割下一个三角形,割下黑色三角形的人胜利,求是否先手必胜 这傻逼题我想了50min...50min! 把这个图转对偶图之后会变成一棵树... 问题转化成了给定一棵树有一个黑色节点每次删除一个叶节点,删除黑色节点的人胜利 如果黑色节点初始就是一个叶节点,那么先手必胜 否则当一个人面临一个黑色节点连接两个白色节点的状态时必败,而没有人会考虑越过这个状态(一旦让黑色只连接一个白色节点的话对方就直接赢了),因此答案只与n的奇偶