[IOI2018]werewolf狼人

好像很久没更博客了呢~

[IOI2018]werewolf狼人

题目链接

洛谷

题解

可以将题意转化为
求从\(S\)出发只经过大于\(L\)的点构成的集合\(∩\)\(E\)只经过小于\(R\)的点是否为空。
我们建\(2\)\(kruskal\)重构树\(A,B\)
\(A\)为每条边的两个点中取较小的点为权值所构成的最大生成树对应的重构树。
\(B\)为每条边的两个点中取较大的点为权值所构成的最小生成树对应的重构树。
接着这\(2\)个集合直接在\(A,B\)上倍增找一下就好了。
同时我们把每个点的开始\(dfs\)序和结束\(dfs\)序求出来。
这就变成了一个序列问题。
直接找个数据结构维护一下就好了。

代码

#include <bits/stdc++.h>

namespace con_fast_io {
char buf[1 << 12], *p1 = buf, *p2 = buf, SR[1 << 23], z[23]; int Z = 0, C = -1;
inline void Ot() { fwrite(SR, 1, C + 1, stdout); C = -1; }
inline void flush() { if (C > 1 << 22) Ot(); }
inline char getc() {
  return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 12, stdin), p1 == p2) ? EOF : *p1++;
}
template<class t> inline void read(t& x) {
  x = 0; int fl = 1; char nc;
  while (nc = getc(), (nc < 48 || nc > 57) && (~nc)) if (nc == 45) fl = -1;
  x = nc - 48; while (nc = getc(), 47 < nc && nc < 58) x = (x << 1) + (x << 3) + (nc ^ 48);
  x *= fl;
};
template<class t> inline void write(t x, char c) {
  int y = 0; if (x < 0) y = 1, x = -x; while (z[++Z] = x % 10 + 48, x /= 10);
  if (y) z[++Z] = '-'; while(SR[++C] = z[Z], Z--); SR[++C] = c; flush();
}
inline void write(char* s) {
  int le = strlen(s);
  for (int i = 0; i < le; i++) SR[++C] = *s++;
  flush();
}
/*char z[23]; int Z = 0;
inline void Ot() {}
template<class t> inline void read(t& x) {
  x = 0; int fl = 1; char nc;
  while (nc = getchar(), (nc < 48 || nc > 57) && (~nc)) if (nc == 45) fl = -1;
  x = nc - 48; while (nc = getchar(), 47 < nc && nc < 58) x = (x << 1) + (x << 3) + (nc ^ 48);
  x *= fl;
}
template<class t> inline void write(t x, char c) {
  Z = 0; int y = 0; if (x < 0) y = 1, x = -x; z[++Z] = c;
  while (z[++Z] = x % 10 + 48, x /= 10);
  if (y) z[++Z] = '-'; while (Z) putchar(z[Z--]);
}
inline void write(char* s) { printf("%s\n", s); }*/
}
using namespace con_fast_io;
const int maxn = 2e5 + 600;
const int maxm = 4e5 + 1500;
const int inf = 0x3f3f3f3f;

int n, m, i, j, k, q, cnto, val[maxn];
struct edge {
  int u, v; edge() { u = v = 0; } edge(int _u, int _v) { u = _u, v = _v; }
} e[maxm];
inline bool cmp1(edge a, edge b) { return std::min(a.u, a.v) > std::min(b.u, b.v); }
inline bool cmp2(edge a, edge b) { return std::max(a.u, a.v) < std::max(b.u, b.v); }
struct ufs_t {
  int fa[maxm];
  inline void init(int j) { for (int i = 1; i <= j; i++) fa[i] = i; }
  int find(int u) { return u == fa[u] ? u : fa[u] = find(fa[u]); }
} ufs;
struct kruskal_rebuild_tree_t {
  int cnte, tim, hd[maxm], ver[maxm], nxt[maxm], fa[maxm][25], st[maxm], ed[maxm];
  int val[maxm], dfn[maxm];
  inline void adde(int u, int v) {
    ver[++cnte] = v, nxt[cnte] = hd[u], hd[u] = cnte;
  }
  void dfs(int u) {
    if (u <= n) dfn[++tim] = u, val[u] = u, st[u] = tim; else st[u] = tim + 1;
    for (int i = 1; i <= 20; i++) fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (int i = hd[u], v; i; i = nxt[i]) {
      v = ver[i];
      fa[v][0] = u;
      dfs(v);
    }
    ed[u] = tim;
  }
  inline void work(int type) {
    ufs.init(n << 1);
    if (!type) std::sort(e + 1, e + m + 1, cmp1);
    else std::sort(e + 1, e + m + 1, cmp2);
    int tot = n;
    for (int i = 1; i <= m; i++) {
      int u = e[i].u, v = e[i].v, w = type ? std::max(u, v) : std::min(u, v);
      int ru = ufs.find(u), rv = ufs.find(v);
      if (ru == rv) continue;
      ufs.fa[ru] = ufs.fa[rv] = ++tot;
      val[tot] = w, adde(tot, ru), adde(tot, rv);
    }
   // exit(0);
    dfs(tot);
  }
  inline int getL(int u, int l) {
    for (int i = 20; ~i; i--) if (val[fa[u][i]] >= l) u = fa[u][i];
    return u;
  }
  inline int getR(int u, int r) {
    for (int i = 20; ~i; i--) if (val[fa[u][i]] <= r) u = fa[u][i];
    return u;
  }
  inline void out() {
    for (int i = 1; i <= n; i++) {
      printf("%d %d %d\n", st[i], ed[i], val[i]);
    }
  }
} A, B;
int rt[maxn * 35], ch[maxn * 35][2], sz[maxn * 35];
inline void cpy(int o1, int o2) {
  ch[o1][0] = ch[o2][0], ch[o1][1] = ch[o2][1], sz[o1] = sz[o2];
}
void modify(int p, int& u, int l, int r) {
  cpy(++cnto, u); sz[u = cnto]++;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (p <= mid) modify(p, ch[u][0], l, mid);
  else modify(p, ch[u][1], mid + 1, r);
}
int query(int ql, int qr, int l, int r, int o1, int o2) {
  if (!(o1 || o2) || ql > r || qr < l) return 0;
  if (ql <= l && r <= qr) return sz[o2] - sz[o1];
  int mid = (l + r) >> 1, res = 0;
  return query(ql, qr, l, mid, ch[o1][0], ch[o2][0]) + query(ql, qr, mid + 1, r, ch[o1][1], ch[o2][1]);
}

int main() {
  read(n), read(m), read(q);
  for (int i = 1, u, v; i <= m; i++) {
    read(u), read(v), u++, v++;
    e[i] = edge(u, v);
  }
  A.work(0), B.work(1), B.val[0] = inf;
//  A.out(), B.out();
  for (int i = 1; i <= n; i++) val[A.dfn[i]] = i;
 // return 0;
  for (int i = 1; i <= n; i++) modify(val[B.dfn[i]], rt[i] = rt[i - 1], 1, n);
 // return 0;
  for (int i = 1, S, E, l, r; i <= q; i++) {
    read(S), read(E), read(l), read(r); S++, E++, l++, r++;
    int a = A.getL(S, l), b = B.getR(E, r);
    write(query(A.st[a], A.ed[a], 1, n, rt[B.st[b] - 1], rt[B.ed[b]]) ? 1 : 0, '\n');
  }
  return Ot(), 0;
}
posted @ 2019-09-08 23:32 _connect 阅读(...) 评论(...) 编辑 收藏
Live2D