UOJ Round #11

A

记忆化一下,直接爆搜即可。

状态数非常少,分析出的上界大约是 \(10^7\) 左右,但实际上只有 \(10^5\) 的样子。

#include <bits/stdc++.h>

#define IL __inline__ __attribute__((always_inline))

#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)

typedef long long LL;

template <class T>
IL bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}

template <class T>
IL bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}

template <class T>
IL T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}

template <class T>
IL T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}

template <class T>
IL T myabs(const T &a) {
  return a > 0 ? a : -a;
}

const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())

namespace Math {
const int MOD = 998244353;

IL int add(int a, int b) {
  a += b;
  return a >= MOD ? a - MOD : a;
}

template <class ...Args>
IL int add(int a, const Args &...args) {
  a += add(args...);
  return a >= MOD ? a - MOD : a;
}

IL int sub(int a, int b) {
  a -= b;
  return a < 0 ? a + MOD : a;
}

IL int mul(int a, int b) {
  return (LL)a * b % MOD;
}

template <class ...Args>
IL int mul(int a, const Args &...args) {
  return (LL)a * mul(args...) % MOD;
}

IL int quickPow(int a, int p) {
  int ret = 1;
  for (; p; p >>= 1, a = mul(a, a)) {
    if (p & 1) {
      ret = mul(ret, a);
    }
  }
  return ret;
}
}

using namespace Math;

const int MAXN = 100 + 5;

using Arr = std::array<int, 100>;
using Node = std::pair<int, Arr>;

Arr s, t;
int n, m;
std::map<Node, int> mp;

int DFS(int c, const Arr &cur) {
  if (c >= m) {
    return cur == t;
  }
  Node now = Node(c, cur);
  auto it = mp.find(now);
  if (it != mp.end()) {
    return it->second;
  }
  Arr t = cur;
  int x = t[0], ans = cur == ::t;
  FOR(i, 0, 3) {
    if (x != i) {
      t[0] = i;
      ans = add(ans, DFS(c + 1, t));
      t[0] = x;
    }
  }
  FOR(i, 1, n) {
    int y = t[i];
    if (y != x) {
      FOR(j, 0, 3) {
        if (x != j && y != j) {
          t[i] = j;
          ans = add(ans, DFS(c + 1, t));
          t[i] = y;
        }
      }
      break;
    }
  }
  return mp[now] = ans;
}

int main() {
  scanf("%d%d", &n, &m);
  FOR(i, 0, n) {
    int x;
    scanf("%d", &x);
    -- x;
    s[i] = x;
  }
  FOR(i, 0, n) {
    int x;
    scanf("%d", &x);
    -- x;
    t[i] = x;
  }
  printf("%d\n", DFS(0, s));
  return 0;
}

B

有一个结论是如果任意点集 \(V\) 都满足 \(E(V) \le 2|V| - 2\),那么这个图就是丛林,反之则不是,可以用拟阵并证明。

那么就很好做了,建一个二分图,边向点连边,边权值是 \(1\),点权值是 \(-2\),跑最大权闭合子图即可。

这样有一个问题是最大权闭合子图权值可能是负的,这个时候网络流会跑出一个空集来,于是你需要强制选一个点(把它的权值改成 \(0\))。

每个点都跑一遍 Dinic 显然不优,换成退流即可。

#include <bits/stdc++.h>

#define IL __inline__ __attribute__((always_inline))

#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)

typedef long long LL;

template <class T>
IL bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}

template <class T>
IL bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}

template <class T>
IL T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}

template <class T>
IL T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}

template <class T>
IL T myabs(const T &a) {
  return a > 0 ? a : -a;
}

const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())

const int MAXN = 6000 + 5, MAXM = 100000 + 5;

namespace NetworkFlow {
int s, t, n, m;

struct Edge {
  int from, to, resi;

  Edge() {}
  Edge(int _f, int _t, int _r) : from(_f), to(_t), resi(_r) {}
} edge[MAXM * 2];

std::vector<int> adj[MAXN];
int cnt;

IL void addEdge(int u, int v, int c) {
  edge[cnt] = Edge(u, v, c), adj[u].push_back(cnt);
  ++ cnt;
  edge[cnt] = Edge(v, u, 0), adj[v].push_back(cnt);
  ++ cnt;
}

IL void build() {
  scanf("%d%d", &n, &m);
  s = n + m + 1, t = n + m + 2;
  For(i, 1, n) {
    addEdge(i, t, 2);
  }
  For(i, 1, m) {
    addEdge(s, i + n, 1);
  }
  For(i, 1, m) {
    int u, v;
    scanf("%d%d", &u, &v);
    addEdge(i + n, u, INF);
    addEdge(i + n, v, INF);
  }
}

int dist[MAXN], vis[MAXN], rc;

IL bool BFS() {
  static int queue[MAXN];
  dist[s] = 0;
  vis[s] = ++ rc;
  int l = 1, r = 0;
  queue[++ r] = s;
  while (l <= r) {
    int u = queue[l ++];
    for (auto &x : adj[u]) {
      Edge &e = edge[x];
      if (e.resi && vis[e.to] != rc) {
        dist[e.to] = dist[u] + 1;
        vis[e.to] = rc;
        queue[++ r] = e.to;
      } 
    }
  }
  return vis[t] == rc;
}

int cur[MAXN];

int DFS(int u, int x) {
  if (!x || u == t) {
    return x;
  }
  int flow = 0, f;
  for (int &i = cur[u]; i < SZ(adj[u]); ++ i) {
    Edge &e = edge[adj[u][i]];
    if (dist[e.to] == dist[u] + 1 && (f = DFS(e.to, mymin(e.resi, x)))) {
      edge[adj[u][i]].resi -= f, edge[adj[u][i] ^ 1].resi += f;
      flow += f, x -= f;
      if (!x) {
        break;
      }
    }
  }
  return flow;
}

IL int dinic(int p = s, int q = t, int init = INF) {
  if (p == q) {
    return init;
  }
  int flow = 0, a = s, b = t;
  s = p, t = q;
  while (init > flow && BFS()) {
    memset(cur, 0, sizeof cur);
    flow += DFS(s, init - flow);
  }
  s = a, t = b;
  return flow;
}

IL bool solve() {
  int w = dinic();
  if (w < m) {
    return 0;
  }
  For(i, 1, n) {
    int a = (i - 1) << 1, b = (i - 1) << 1 | 1, u = edge[a].from, v = edge[a].to, p = edge[b].resi;
    dinic(t, v, p), dinic(u, s, p);
    w -= p;
    edge[a].resi = edge[b].resi = 0;
    w += dinic(s, t, 2);
    if (w < m) {
      return 0;
    }
    edge[a].resi = 2;
  }
  return 1;
}
}

int main() {
#ifndef ONLINE_JUDGE
  freopen("forest.in", "r", stdin);
#endif
  NetworkFlow::build();
  puts(NetworkFlow::solve() ? "Yes" : "No");
  return 0;
}

C

参照吉如一的集训队论文,用 Segment Tree Beats 的方法维护操作 2,其他操作把区间的最小值和非最小值部分分开维护就行了。

#include <bits/stdc++.h>

#define IL __inline__ __attribute__((always_inline))

#define For(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++ i)
#define FOR(i, a, b) for (int i = (a), i##end = (b); i < i##end; ++ i)
#define Rep(i, a, b) for (int i = (a), i##end = (b); i >= i##end; -- i)
#define REP(i, a, b) for (int i = (a) - 1, i##end = (b); i >= i##end; -- i)

typedef long long LL;

template <class T>
IL bool chkmax(T &a, const T &b) {
  return a < b ? ((a = b), 1) : 0;
}

template <class T>
IL bool chkmin(T &a, const T &b) {
  return a > b ? ((a = b), 1) : 0;
}

template <class T>
IL T mymax(const T &a, const T &b) {
  return a > b ? a : b;
}

template <class T>
IL T mymin(const T &a, const T &b) {
  return a < b ? a : b;
}

template <class T>
IL T myabs(const T &a) {
  return a > 0 ? a : -a;
}

const int INF = 0X3F3F3F3F;
const double EPS = 1E-8, PI = acos(-1.0);

#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define OK DEBUG("Passing [%s] in LINE %d...\n", __FUNCTION__, __LINE__)
#define SZ(x) ((int)(x).size())

struct Input {
  char buf[1 << 25], *s;

  Input() {
#ifndef ONLINE_JUDGE
    freopen("array.in", "r", stdin);
    freopen("array.out", "w", stdout);
#endif
    fread(s = buf, 1, 1 << 25, stdin);
  }

  friend Input &operator>>(Input &io, int &x) {
    x = 0;
    int p = 1;
    while (!isdigit(*io.s)) {
      if (*io.s == '-') {
        p = -1;
      }
      ++ io.s;
    }
    while (isdigit(*io.s)) {
      x =  x * 10 + *io.s ++ - '0';
    }
    x *= p;
    return io;
  }
} cin;

const int MAXN = 500000 + 5;

struct SegmentTree {
  using Arr = std::array<int, MAXN * 4>;

  Arr min, min_num, min_mark, sec, mark, min_hmin, min_pmark, hmin, pmark;

#define lc (o << 1)
#define rc (o << 1 | 1)
  void pushUp(int o, int l, int r) {
    int mid = (l + r) >> 1;
    min_mark[o] = mark[o] = min_pmark[o] = pmark[o] = 0;
    if (min[lc] < min[rc]) {
      min[o] = min[lc], min_num[o] = min_num[lc];
      min_hmin[o] = min_hmin[lc], hmin[o] = min_hmin[rc];
      if (min_num[lc] != mid - l + 1) {
        chkmin(hmin[o], hmin[lc]);
      }
      if (min_num[rc] != r - mid) {
        chkmin(hmin[o], hmin[rc]);
      }
      sec[o] = min_num[lc] == mid - l + 1 ? min[rc] : mymin(sec[lc], min[rc]);
    } else if (min[lc] > min[rc]) {
      min[o] = min[rc], min_num[o] = min_num[rc];
      min_hmin[o] = min_hmin[rc], hmin[o] = min_hmin[lc];
      if (min_num[lc] != mid - l + 1) {
        chkmin(hmin[o], hmin[lc]);
      }
      if (min_num[rc] != r - mid) {
        chkmin(hmin[o], hmin[rc]);
      }
      sec[o] = min_num[rc] == r - mid ? min[lc] : mymin(sec[rc], min[lc]);
    } else {
      min[o] = min[lc], min_num[o] = min_num[lc] + min_num[rc];
      min_hmin[o] = mymin(min_hmin[lc], min_hmin[rc]);
      if (min_num[lc] != mid - l + 1 && min_num[rc] != r - mid) {
        hmin[o] = mymin(hmin[lc], hmin[rc]);
      } else if (min_num[lc] != mid - l + 1) {
        hmin[o] = hmin[lc];
      } else if (min_num[rc] != r - mid) {
        hmin[o] = hmin[rc];
      } else {
        hmin[o] = 0;
      }
      if (min_num[lc] == mid - l + 1) {
        sec[o] = sec[rc];
      } else if (min_num[rc] == r - mid) {
        sec[o] = sec[lc];
      } else {
        sec[o] = mymin(sec[lc], sec[rc]);
      }
    }
  }

  void pushDown(int o, int l, int r) {
    int mid = (l + r) >> 1;
    if (min_pmark[o]) {
      if (min[lc] < min[rc]) {
        chkmin(min_hmin[lc], min[lc] + min_pmark[o]);
        chkmin(min_pmark[lc], min_mark[lc] + min_pmark[o]);
      } else if (min[lc] < min[rc]) {
        chkmin(min_hmin[rc], min[rc] + min_pmark[o]);
        chkmin(min_pmark[rc], min_mark[rc] + min_pmark[o]);
      } else {
        chkmin(min_hmin[lc], min[lc] + min_pmark[o]), chkmin(min_hmin[rc], min[rc] + min_pmark[o]);
        chkmin(min_pmark[lc], min_mark[lc] + min_pmark[o]), chkmin(min_pmark[rc], min_mark[rc] + min_pmark[o]);
      }
      min_pmark[o] = 0;
    }
    if (pmark[o]) {
      if (min[lc] < min[rc]) {
        chkmin(min_hmin[rc], min[rc] + pmark[o]);
        chkmin(min_pmark[rc], min_mark[rc] + pmark[o]);
      } else if (min[lc] > min[rc]) {
        chkmin(min_hmin[lc], min[lc] + pmark[o]);
        chkmin(min_pmark[lc], min_mark[lc] + pmark[o]);
      }
      if (min_num[lc] != mid - l + 1) {
        chkmin(hmin[lc], sec[lc] + pmark[o]);
        chkmin(pmark[lc], mark[lc] + pmark[o]);
      }
      if (min_num[rc] != r - mid) {
        chkmin(hmin[rc], sec[rc] + pmark[o]);
        chkmin(pmark[rc], mark[rc] + pmark[o]);
      }
      pmark[o] = 0;
    }
    int x = min[lc], y = min[rc];
    if (min_mark[o]) {
      if (x < y) {
        min[lc] += min_mark[o], min_mark[lc] += min_mark[o];
      } else if (x > y) {
        min[rc] += min_mark[o], min_mark[rc] += min_mark[o];
      } else {
        min[lc] += min_mark[o], min[rc] += min_mark[o], min_mark[lc] += min_mark[o], min_mark[rc] += min_mark[o];
      }
      min_mark[o] = 0;
    }
    if (mark[o]) {
      if (x < y) {
        min[rc] += mark[o], min_mark[rc] += mark[o];
      } else if (x > y) {
        min[lc] += mark[o], min_mark[lc] += mark[o];
      }
      if (min_num[lc] != mid - l + 1) {
        sec[lc] += mark[o], mark[lc] += mark[o];
      }
      if (min_num[rc] != r - mid) {
        sec[rc] += mark[o], mark[rc] += mark[o];
      }
      mark[o] = 0;
    }
  }

  void build(int o, int l, int r, int *a) {
    if (l == r) {
      min[o] = min_hmin[o] = a[l];
      min_num[o] = 1;
      return;
    }
    int mid = (l + r) >> 1;
    build(lc, l, mid, a);
    build(rc, mid + 1, r, a);
    pushUp(o, l, r);
  }

  void modify1(int o, int l, int r, int a, int b, int x) {
    if (l >= a && r <= b) {
      min[o] += x, min_mark[o] += x;
      chkmin(min_hmin[o], min[o]), chkmin(min_pmark[o], min_mark[o]);
      if (min_num[o] != r - l + 1) {
        sec[o] += x, mark[o] += x;
        chkmin(hmin[o], sec[o]), chkmin(pmark[o], mark[o]); 
      }
      return;
    }
    pushDown(o, l, r);
    int mid = (l + r) >> 1;
    if (a <= mid) {
      modify1(lc, l, mid, a, b, x);
    }
    if (b > mid) {
      modify1(rc, mid + 1, r, a, b, x);
    }
    pushUp(o, l, r);
  }

  void modify2(int o, int l, int r, int a, int b, int x) {
    if (l >= a && r <= b) {
      if (x <= min[o]) {
        return;
      } else if (min_num[o] == r - l + 1 || x < sec[o]) {
        int d = x - min[o];
        min[o] += d, min_mark[o] += d;
        chkmin(min_hmin[o], min[o]), chkmin(min_pmark[o], min_mark[o]);
        return;
      }
    }
    pushDown(o, l, r);
    int mid = (l + r) >> 1;
    if (a <= mid) {
      modify2(lc, l, mid, a, b, x);
    }
    if (b > mid) {
      modify2(rc, mid + 1, r, a, b, x);
    }
    pushUp(o, l, r);
  }

  int query1(int o, int l, int r, int a, int b) {
    if (l >= a && r <= b) {
      return min[o];
    }
    pushDown(o, l, r);
    int mid = (l + r) >> 1, ans = INT_MAX;
    if (a <= mid) {
      chkmin(ans, query1(lc, l, mid, a, b));
    }
    if (b > mid) {
      chkmin(ans, query1(rc, mid + 1, r, a, b));
    }
    return ans;
  }

  int query2(int o, int l, int r, int a, int b) {
    if (l >= a && r <= b) {
      return min_num[o] == r - l + 1 ? min_hmin[o] : mymin(min_hmin[o], hmin[o]);
    }
    pushDown(o, l, r);
    int mid = (l + r) >> 1, ans = INT_MAX;
    if (a <= mid) {
      chkmin(ans, query2(lc, l, mid, a, b));
    }
    if (b > mid) {
      chkmin(ans, query2(rc, mid + 1, r, a, b));
    }
    return ans;
  }
} seg;

int a[MAXN];

int main() {
  int n, m;
  cin >> n >> m;
  For(i, 1, n) {
    cin >> a[i];
  }
  seg.build(1, 1, n, a);
  For(i, 1, m) {
    int opt;
    cin >> opt;
    if (opt == 1) {
      int l, r, c;
      cin >> l >> r >> c;
      seg.modify1(1, 1, n, l, r, c);
    } else if (opt == 2) {
      int l, r, d;
      cin >> l >> r >> d;
      seg.modify2(1, 1, n, l, r, d);
    } else if (opt == 3) {
      int l, r;
      cin >> l >> r;
      printf("%d\n", seg.query1(1, 1, n, l, r));
    } else {
      int l, r;
      cin >> l >> r;
      printf("%d\n", seg.query2(1, 1, n, l, r));
    }
  }
  return 0;
}
posted @ 2020-01-14 08:12  sjkmost  阅读(188)  评论(0编辑  收藏  举报