列表

详情


NC20804. [NOI2017]分身术

描述

“”分!身!术!” —— 小 P 平面上有 n 个小 P 的分身。定义一组分身占领的区域为覆盖这组分身的最小凸多 边形。小 P 能力有限,每一时刻都会有若干分身消失。但在下一时刻之前,小 P 会使用 ‘‘分!身!术!” 使得这些消失的分身重新出现在原来的位置。小 P 想知道,每一时刻分身消失后, 剩下的分身占领的区域面积是多少? 

输入描述

输入第一行包含两个正整数 n, m,描述初始时分身的个数,和总时刻数。

接下来 n 行,第 i 行有两个整数 xi
, yi ,描述第 i 个分身的位置。

接下来 m 行,每行的第一个整数 k 表示这一时刻有 k 个分身消失。

接下来有 k 个
非负整数 c1, c2, · · · ck,用于生成消失的分身的编号。

生成方式如下:

设上一个时刻中,分身占领面积的两. 倍. 为 S。则该时刻消失的分身 p1, p2, . . . , pk 的
编号为:
pi = [(S + ci) mod n] + 1

特别的,在第一个时刻,我们认为上一个时刻中,S = −1 ,即:第一个时刻消失
的分身 p1, p2, . . . , pk 的编号为:
pi = [(−1 + ci) mod n] + 1

输出描述

按给出时刻的顺序依次输出 m 行,每行一个整数,表示该时刻剩余分身所占领区
域面积的两. 倍. 。

示例1

输入:

6 2
-1 0
-1 -1
0 -1
1 0
0 1
0 0
3 1 3 6
2 0 1

输出:

3
2

说明:

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 1819ms, 内存消耗: 73696K, 提交时间: 2019-01-07 19:29:00

#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define CLOCKWISE 1
#define ANTICLOCKWISE -1
#define LEFT_CONVEX 1
#define RIGHT_CONVEX -1
#define CONSTRUCT_LAYERS 1
#define SINGLE_QUERY -1
#define MAX_N 100000
#define MAX_LAYERS 100
#define INF (~0U>>1)
using namespace std;

struct Point {
 int x, y;
 int layer, pos;
 int idx;
};
long long cx(Point *a, Point *b, Point *c) {
 return (long long) (b->x-a->x)*(c->y-a->y) - (long long) (b->y-a->y)*(c->x-a->x);
}
long long dj(Point *a, Point *b, Point *c) {
 return (long long) (b->x-a->x)*(c->x-a->x) + (long long) (b->y-a->y)*(c->y-a->y);
}
struct Hull {
 Point **p;
 int n;
 Hull (int n) {
  p = (Point **) malloc(sizeof(Point *) * (n+2));
  this->n = n;
 }
 Point *pos(int x) { while (x <= 0) x += n; while (x >= n) x -= n; return p[x]; }
};
struct Convex {
 Point **p;
 int h, t;
 int sign;
 bool refine(Point *a) { bool dom = false; while (h < t && cx(p[t-1], p[t], a) * sign >= 0) --t, dom = true; return dom; }
 void push(Point *a)   { refine(a); p[++t] = a; }
 Point *peek()     { return h == t ? NULL : p[h+1]; }
 Point *pop()          { return p[++h]; }
 Point *top()    { return p[t]; }
};
struct Opening {
 Point *a, *b;
 int apos, bpos;
 Convex *a_con, *b_con;
};
struct Segment {
 int l, r;
};

long long *v[MAX_LAYERS+10];
long long area;
int removed[MAX_N+10];
int idx[MAX_N+10];

Point *o;
Point *p[MAX_N+10], *p2[MAX_N+10], *q[MAX_N+10], *rp[MAX_N+10];
Point **point_heap;
int p_point_heap;

Hull *layer[MAX_LAYERS+10];

Opening *opening[MAX_LAYERS+10];
Opening **s_op, **t_op, **n_op;
Opening *open;

Convex *convex[MAX_LAYERS+10];
int n_convex;

Segment segment[MAX_LAYERS+10];

bool cmp_pointrp(Point *a, Point *b) {
 return a->layer == b->layer ? a->pos < b->pos : a->layer < b->layer;
}
bool cmp_point2d(Point *a, Point *b) {
 return a->x == b->x ? a->y < b->y : a->x < b->x;
}
bool cmp_opening(Opening *a, Opening *b) {
 return a->apos < b->apos;
}
void init() {
 o = new Point();
 o->x = o->y = 0;
 point_heap = (Point **) malloc(sizeof(Point*) * (4 * MAX_LAYERS * MAX_LAYERS));
 open = new Opening();
 open->apos = -INF;
 open->bpos = INF;
}
void clear_for_query() {
    opening[0] = open;
 s_op = n_op = opening;
 t_op = s_op+1;
 p_point_heap = 0;
 area = v[1][0];
}
Point **point_malloc(int n) {
 Point **p = point_heap + (p_point_heap);
 p_point_heap += n;
 return p;
}
Convex *new_convex(int sign, Point *a) {
 Convex *con = new Convex();
 con->p = point_malloc(MAX_LAYERS+2);
 con->h = 1, con->t = 0;
 con->sign = sign;
 con->push(a);
 return con;
}
Opening *new_opening(Point *a, Point *b, Point *pa, Point *pb, Convex *a_con, Convex *b_con) {
 Opening *op = new Opening();
 op->a = a, op->b = b;
 op->apos = pa->pos, op->bpos = pb->pos;
 op->a_con = a_con;
 op->b_con = b_con;
 if (op->apos > op->bpos)
  op->bpos += layer[pa->layer]->n;
 return op;
}
long long cxsum(Point *a, Point *b) {
 long long *vp = v[a->layer];
 return a->pos <= b->pos ? vp[b->pos]-vp[a->pos] : vp[0] - (vp[a->pos]-vp[b->pos]);
}
Point *find_tangle(Hull *hull, Point *a, int sign) {
 int n = hull->n;
 int bias = sign == -1;
 if (n == 0)
  return NULL;
 if (n == 1)
  return hull->p[n];
 
 Point *b = hull->pos(sign+bias);

 bool dom = cx(a, hull->pos(sign+bias), hull->pos(bias)) * sign <= 0;
 int l = 2, r = n, j, an = 1;
 
 for (; j = (l+r)>>1, l <= r; ) {
  if (cx(a, b, hull->pos(sign*j+bias)) * sign <= 0) {
   if (dom) r = j-1;
   else l = j+1;
  }
  else if (cx(a, hull->pos(sign*j+bias), hull->pos(sign*(j-1)+bias)) * sign <= 0)
   an = j, l = j+1;
  else r = j-1;
 } return hull->pos(sign*an+bias);
}
bool find_new_opening(Hull *hull, Point *a, Point *b, Convex *a_con, Convex *b_con) {
 Point *s1 = a, *s2 = b;
 Point *pa, *pb;
 while (a->idx != b->idx) {
  pa = find_tangle(hull, a, CLOCKWISE);
  pb = find_tangle(hull, b, ANTICLOCKWISE);

  if (a_con->peek() && (pa == NULL || cx(a, pa, a_con->peek()) >= 0)) {
   area += cx(o, a, a_con->peek());
   a = a_con->pop();
  }
  else if (b_con->peek() && (pb == NULL || cx(b, b_con->peek(), pb) >= 0)) {
   area += cx(o, b_con->peek(), b);
   b = b_con->pop();
  }
  else {
   area += cx(o, a, pa) + cx(o, pb, b) + cxsum(pa, pb);
   *(++n_op) = new_opening(a, b, pa, pb, a_con, b_con);
   return 1;
  }
 }
 return 0;
}
void layer_by_layer(int m, Point **rp) {
 Point *a, *b, *ia, *ib, *a_del, *b_del;
 Convex *a_con, *b_con;
 Segment *seg_s, *seg, *seg_end;
 Hull *cur, *hull;
 sort(rp+1, rp+m+1, cmp_pointrp);
 int s = 1, t;

    int num = 0;
    Point *record = NULL;
    Point *pa, *pb;

 for (int i = 1; i <= MAX_LAYERS; ++i, s = t) {
  cur = layer[i], hull = layer[i+1];

        if (num == 1) {
            pa = find_tangle(cur, record, CLOCKWISE);
            pb = find_tangle(cur, record, ANTICLOCKWISE);
            *s_op = new_opening(record, record, pa, pb, new_convex(LEFT_CONVEX, record), new_convex(RIGHT_CONVEX, record));
            area = cxsum(pa, pb) + cx(o, record, pa) + cx(o, pb, record);
        }

  if (s > m || rp[s]->layer != i)
   break;
  t = s;
  while (t <= m && rp[t]->layer == rp[s]->layer)
   ++t;

        if (t == s) {
            break;
        }
        if (cur->n - (t-s) == 1 && num == 0) {
            num = 1;
            for (int j = 0; j < cur->n; ++j)
                if (removed[cur->p[j]->idx] == false) {
                    record = cur->p[j];
                    break;
                }
            continue;
        }
        if (cur->n - (t-s) == 0 && num == 0) {
            area = v[i+1][0];
            continue;
        }

  if (t - s == cur->n) {
            if (num == 1)
                continue;
   for (Opening **p_op = s_op; p_op != t_op; ++p_op) {
    Opening *op = *p_op;
    area -= cx(o, op->a, cur->pos(op->apos));
    area -= cx(o, cur->pos(op->bpos), op->b);
    area -= cxsum(cur->pos(op->apos), cur->pos(op->bpos));
    find_new_opening(hull, op->a, op->b, op->a_con, op->b_con);
   }
   s_op = t_op;
   t_op = n_op + 1;
   sort(s_op, t_op, cmp_opening);
   continue;
  }

  seg_s = seg = segment;
  for (int j = s+1; j < t; ++j)
   if (rp[j]->pos != rp[j-1]->pos+1) {
    seg->r = rp[j-1]->pos;
    (++seg)->l = rp[j]->pos;
   }
  if (rp[s]->pos == 1 && rp[t-1]->pos == cur->n) {
   seg_s->l = seg->l - cur->n;
   --seg;
  }
  else seg_s->l = rp[s]->pos, seg->r = rp[t-1]->pos;
  int n_seg = seg-seg_s+1;
  
  while (seg->r < 2*cur->n) {
   ++seg;
   seg->r = (seg-n_seg)->r + cur->n;
   seg->l = (seg-n_seg)->l + cur->n;
  }
  if (num <= 0) seg_end = seg_s + n_seg;
  else seg_end = seg+1;
  seg = seg_s;

  for (Opening **p_op = s_op; p_op != t_op; ++p_op) {
   Opening *op = *p_op; 
   while (seg != seg_end && seg->r < op->apos)
    ++seg;
   while (seg != seg_end && seg->l <= op->bpos) {
    ia = cur->pos(seg->l-1);
    ib = cur->pos(seg->r+1);

    if (seg->l <= op->apos) {
     a = op->a, a_con = op->a_con;
     a_del = cur->pos(op->apos);
     area -= cx(o, a, a_del);
    }
    else {
     a = ia, a_con = new_convex(LEFT_CONVEX, a);
     a_del = ia;
    }
    if (seg->r >= op->bpos) {
     b = op->b, b_con = op->b_con;
     b_del = cur->pos(op->bpos);
     area -= cx(o, b_del, b);
    }
    else {
     b = ib, b_con = new_convex(RIGHT_CONVEX, b);
     b_del = ib;
    }
    if (b == ib) {
     while (a_con->h < a_con->t && cx(a, b, a_con->top()) <= 0) --a_con->t;
     a_con->push(b);
    }
    else if (a == ia) {
     while (b_con->h < b_con->t && cx(a, b, b_con->top()) <= 0) --b_con->t;
     b_con->push(a);
    }
    if (cx(a, b, ia) > 0 && (a_con->refine(ia) || b_con->refine(ia)))
     a_con->push(ia), b_con->push(ia);
    if (cx(a, b, ib) > 0 && (a_con->refine(ib) || b_con->refine(ib)))
     b_con->push(ib), a_con->push(ib);
    area -= cxsum(a_del, b_del);
   
    find_new_opening(hull, a, b, a_con, b_con);
    
    if (seg->r >= op->bpos)
     break;
    ++seg;
   }
  }
        num += cur->n - (t-s);
  s_op = t_op;
  t_op = n_op + 1;
  sort(s_op, t_op, cmp_opening);
 }
}
void bruteforce(int n, Point **p, int &t, Point **q, int mode) {
 int h;
 h = 1, t = 0;
 for (int i = 1; i <= n; ++i) {
  if (mode == CONSTRUCT_LAYERS && p[i]->layer != 0)
   continue;
  if (mode == SINGLE_QUERY && removed[p[i]->idx] == true)
   continue;
  while (t > 1 && cx(q[t-1], q[t], p[i]) >= 0) --t;
  q[++t] = p[i];
 }
 h = t, --t;
 for (int i = n; i >= 1; --i) {
  if (mode == CONSTRUCT_LAYERS && p[i]->layer != 0)
   continue;
  if (mode == SINGLE_QUERY && removed[p[i]->idx] == true)
   continue;
  while (h < t && cx(q[t-1], q[t], p[i]) >= 0) --t;
  q[++t] = p[i];
 }
 if (t == 1) t = 2, q[t+1] = q[1];
 if (t <= 0) t = 1;
}
void construct_layers(int n, Point **p, Point **q) {
 int t;
 sort(p+1, p+n+1, cmp_point2d);
 for (int i = 1; i <= MAX_LAYERS+1; ++i) {
  bruteforce(n, p, t, q, CONSTRUCT_LAYERS);
  Hull *hull = new Hull(t-1);
  layer[i] = hull;
  if (t == 1)
   break;
  for (int j = 1; j < t; ++j) {
   q[j]->layer = i;
   q[j]->pos = j;
   hull->p[j] = q[j];
  }
  hull->p[0] = hull->p[t-1];
  hull->p[t] = hull->p[1];
  long long *vp = (long long *) malloc(sizeof(long long)*(t+2));
  for (int j = 1; j <= t; ++j)
   vp[j] = j == 1 ? 0 : vp[j-1] + cx(o, q[j-1], q[j]);
  vp[0] = vp[t];
  v[i] = vp;
 }
}
int main() {
 init();
 int n, m;
 cin >> n >> m;
 for (int i = 1; i <= n; ++i) {
  int x, y;
  Point *pt = new Point();
  scanf("%d %d", &x, &y);
  pt->x = x, pt->y = y;
  pt->idx = i;
  p[i] = p2[i] = pt;
 }
 construct_layers(n, p2, q);
 for (int i = 1; i <= m; ++i) {
  int rc = i == 1 ? (n-1) : (-area) % n;
  clear_for_query();

  int x, k, t = 0;
  scanf("%d", &k);
  for (int j = 1; j <= k; ++j) {
   scanf("%d", idx+j);
   idx[j] = (idx[j] + 1LL*rc) % n + 1;
   
            if (removed[idx[j]] == true)
    continue;
   removed[idx[j]] = true;
   
            if (p[idx[j]]->layer != 0)
    rp[++t] = p[idx[j]];
  }

        layer_by_layer(t, rp);

  for (int j = 1; j <= k; ++j)
            removed[idx[j]] = false;

  cout << -area << endl;
 }
}

上一题