APIO2019 简要题解

终点 究竟有多远
那丧钟 倒数着轮回
我等待 人生的终结
却又不舍 这个世间

T1 奇怪装置

易得周期为 B ⋅ A gcd ⁡ ( A , B + 1 ) B \cdot \frac{A}{\gcd(A,B+1)} Bgcd(A,B+1)A,排序离散化即可。 Θ ( n log ⁡ n ) \Theta(n\log n) Θ(nlogn)

#include 

#include 

using namespace std;

typedef long long ll;

const int N = 1000010;

int n;
ll a, b, period;
pair<ll, int> modi[N * 2];

ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }

int main() {
  scanf("%d%lld%lld", &n, &a, &b);
  ll v = a / gcd(a, b + 1);
  if (3e18 / v < b) period = 3e18;
  else period = v * b;
  for (int i = 1; i <= n; ++i) {
    ll l, r;
    scanf("%lld%lld", &l, &r);
    if (++r - l >= period) {
      printf("%lld\n", period);
      return 0;
    }
    l %= period; r %= period;
    if (l < r) {
      modi[i * 2 - 1] = make_pair(l, 1);
      modi[i * 2] = make_pair(r, -1);
    } else {
      modi[i * 2 - 1] = make_pair(l, 1);
      modi[i * 2] = make_pair(r, -1);
      ++modi[0].second;
    }
  }
  modi[n * 2 + 1].first = period;
  sort(modi + 1, modi + n * 2 + 1);
  ll ans = 0;
  int cnt = 0;
  for (int i = 0; i <= n * 2; ++i)
    ans += bool(cnt += modi[i].second) * (modi[i + 1].first - modi[i].first);
  printf("%lld\n", ans);
  return 0;
}

T2 桥梁

按时间分块。这样每次都是一个缩小的图上考察连通性。 Θ ( q n log ⁡ n ) \Theta(q \sqrt{n\log n}) Θ(qnlogn )

#include 
#include 
#include 

#include 
#include 
#include 

#define LOG(FMT...) fprintf(stderr, FMT)

using namespace std;

struct Node {
  int u, v, w;

  Node() : u(), v(), w() {}

  Node(int u, int v, int w) : u(u), v(v), w(w) {}

  bool operator>(const Node& rhs) const { return w > rhs.w; }
};

struct E {
  int v;
  E* next;
};

const int N = 50010, M = 100010, B = 3100;

int n, m, q;
Node e[M];
bool tag[M], vis[M];
int opt[M], x[M], y[M], ans[M];
pair<int, int> ed[M * 2];
int f[N], sz[N];
int req[B];

E pool[B * 2], *g[N];
E* ptop;

void adde(int u, int v) {
  E* p = ptop++;
  p->v = v;
  p->next = g[u];
  g[u] = p;
}

int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }

int dfs(int u) {
  vis[u] = true;
  int ret = sz[u];
  for (E* p = g[u]; p; p = p->next)
    if (!vis[p->v])
      ret += dfs(p->v);
  return ret;
}

int main() {
#ifdef LBT
  freopen("test.in", "r", stdin);
  int nol_cl = clock();
#endif
  scanf("%d%d", &n, &m);
  for (int i = 1; i <= m; ++i)
    scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
  scanf("%d", &q);
  for (int i = 1; i <= q; ++i)
    scanf("%d%d%d", &opt[i], &x[i], &y[i]);
  int b = sqrt(n * log2(n));
  if (b < 1) b = 1;
  for (int l = 1; l <= q; l += b) {
    int r = min(q, l + b - 1);
    int edc = 0, rc = 0;
    memset(tag, 0, sizeof(tag));
    for (int i = l; i <= r; ++i)
      if (opt[i] == 1)
        tag[x[i]] = true;
      else
        ed[++edc] = make_pair(y[i], -i);
    for (int i = 1; i <= m; ++i)
      if (!tag[i])
        ed[++edc] = make_pair(e[i].w, i);
      else
        req[++rc] = i;
    sort(ed + 1, ed + edc + 1, greater<pair<int, int> >());
    iota(f + 1, f + n + 1, 1);
    fill(sz + 1, sz + n + 1, 1);
    for (int i = 1; i <= edc; ++i) {
      if (ed[i].second > 0) {
        int u = find(e[ed[i].second].u), v = find(e[ed[i].second].v);
        if (u != v) {
          sz[u] += sz[v];
          f[v] = u;
        }
      } else {
        ptop = pool;
        for (int j = -ed[i].second; j >= l; --j) {
          if (opt[j] == 1 && !vis[x[j]]) {
            vis[x[j]] = true;
            if (y[j] >= ed[i].first) {
              int u = find(e[x[j]].u), v = find(e[x[j]].v);
              adde(u, v);
              adde(v, u);
            }
          }
        }
        for (int j = 1; j <= rc; ++j)
          if (!vis[req[j]]) {
            if (e[req[j]].w >= ed[i].first) {
              int u = find(e[req[j]].u), v = find(e[req[j]].v);
              adde(u, v);
              adde(v, u);
            }
          } else
            vis[req[j]] = false;
        ans[-ed[i].second] = dfs(find(x[-ed[i].second]));
        for (int j = 1; j <= rc; ++j) {
          int u = find(e[req[j]].u), v = find(e[req[j]].v);
          g[u] = g[v] = NULL;
          vis[u] = vis[v] = false;
        }
        vis[find(x[-ed[i].second])] = false;
      }
    }
    for (int i = l; i <= r; ++i)
      if (opt[i] == 1)
        e[x[i]].w = y[i];
  }
  for (int i = 1; i <= q; ++i)
    if (ans[i])
      printf("%d\n", ans[i]);

#ifdef LBT
  LOG("Time: %dms\n", int ((clock()
                            -nol_cl) / (double)CLOCKS_PER_SEC * 1000));
#endif
  return 0;
}

T3 路灯

按道路从左至右扫描线,维护一个类单调栈状物,转三维偏序。 Θ ( n log ⁡ 2 n ) \Theta(n\log^2 n) Θ(nlog2n)

#include 

#include 
#include 
#include 

#define LOG(FMT...)

using namespace std;

struct Node {
  int x, y, v;

  Node() : x(), y(), v() {}

  Node(int x, int y, int v) : x(x), y(y), v(v) {}

  bool operator<(const Node& rhs) const {
    if (x != rhs.x) return x < rhs.x;
    return y < rhs.y;
  }
};

const int N = 300010;

int n, q, fwn, cnt;
char s[N];
int state[N], fw[N], ans[N];
map<int, pair<int, int> > sg;
bool isQry[N];
vector<pair<int, int> > seg[N], qq[N];
Node seq[N * 8];

int lowBit(int k) { return k & -k; }

void ch(int k, int x) {
  for (; k <= fwn; k += lowBit(k))
    fw[k] += x;
}

int qry(int k) {
  int ret = 0;
  for (; k; k -= lowBit(k))
    ret += fw[k];
  return ret;
}

void dc(int l, int r) {
  if (l == r) return;
  int mid = l + ((r - l) >> 1);
  dc(l, mid); dc(mid + 1, r);
  int pt = mid + 1;
  for (int i = l; i <= mid; ++i) {
    while (pt <= r && seq[pt] < seq[i]) {
      if (seq[pt].v >= N) {
        ans[seq[pt].v - N] += qry(seq[pt].y);
      }
      ++pt;
    }
    if (seq[i].v < N)
      ch(seq[i].y, seq[i].v);
  }
  while (pt <= r) {
    if (seq[pt].v >= N) {
      ans[seq[pt].v - N] += qry(seq[pt].y);
    }
    ++pt;
  }
  for (int i = l; i <= mid; ++i)
    if (seq[i].v < N)
      ch(seq[i].y, -seq[i].v);
  inplace_merge(seq + l, seq + mid + 1, seq + r + 1);
}

void cut(int p) {
  if (p == 0 || p == q) return;
  map<int, pair<int, int>>::iterator it = sg.lower_bound(p);
  if (it->first == p) return;
  int l, x, r = it->first;
  tie(l, x) = it->second;
  seq[++cnt] = Node(x, r, -p + l - 1);
  seq[++cnt] = Node(x, p, p - l + 1);
  it->second.first = p + 1;
  sg.insert(make_pair(p, make_pair(l, x)));
}

int main() {
  scanf("%d%d%s", &n, &q, s + 1);
  fwn = q;
  for (int i = 1; i <= n; ++i)
    state[i] = s[i] == '0';
  for (int i = 1; i <= q; ++i) {
    int x;
    scanf("%s%d", s, &x);
    if (s[0] == 't') {
      if (state[x]) {
        seg[x].push_back(make_pair(state[x], i));
        state[x] = 0;
      } else
        state[x] = i + 1;
    } else {
      int y;
      scanf("%d", &y);
      qq[y - 1].push_back(make_pair(i, x));
      isQry[i] = true;
    }
  }
  for (int i = 1; i <= n; ++i)
    if (state[i] && state[i] <= q)
      seg[i].push_back(make_pair(state[i], q));
  sg.insert(make_pair(q, make_pair(1, 1)));
  seq[++cnt] = Node(1, q, q);
  for (int i = 1; i <= n; ++i) {
    for (int j = 0; j < seg[i].size(); ++j) {
      int l, r;
      tie(l, r) = seg[i][j];
      cut(l - 1);
      cut(r);
      for (auto it = sg.lower_bound(l); it != sg.end() && it->first <= r; sg.erase(it++))
        seq[++cnt] = Node(it->second.second, it->first, -(it->first - it->second.first + 1));
      seq[++cnt] = Node(i + 1, r, r - l + 1);
      sg.insert(make_pair(r, make_pair(l, i + 1)));
    }
    for (const auto& qr : qq[i]) {
      auto it = sg.lower_bound(qr.first);
      if (it->second.second <= qr.second) {
        ans[qr.first] += qr.first - it->second.first + 1;
      }
      if (it != sg.begin()) {
        --it;
        seq[++cnt] = Node(qr.second, it->first, qr.first + N);
      }
    }
  }
  dc(1, cnt);
  for (int i = 1; i <= q; ++i)
    if (isQry[i])
      printf("%d\n", ans[i]);
  return 0;
}

你可能感兴趣的:(题集/比赛题解)