#include<iostream> usingnamespace std; constint N = 1005; int G[N][N]; int tim[N * N]; int n, m, ans[N * N]; intmain(){ cin >> n >> m; for (int i = 1; i <= m; i++) { int u, v; cin >> u >> v; G[u][v] = i; } for (int k = n; k >= 1; k--) { for (int i = k + 1; i <= n; i++) { tim[min(G[k][i], G[i][k])]++; } for (int i = 1; i <= n; i++) { if (!G[i][k]) { continue; } int nowid = G[i][k]; if (i > k) { for (int j = 1; j < k; j++) { G[i][j] = max(G[i][j], min(nowid, G[k][j])); } } else { for (int j = 1; j <= n; j++) { G[i][j] = max(G[i][j], min(nowid, G[k][j])); } } } } ans[m + 1] = n; for (int i = m; i >= 1; i--) { ans[i] = ans[i + 1] + tim[i]; } for (int i = 1; i <= m + 1; i++) { cout << ans[i] << " "; } return0; }
D2T1 宝石
概括下题意就是找到 $ u \rightarrow v$ 路径上最长的连续子序列,只需要按照给出个排列 p 编号即可
#include<algorithm> #include<cstring> #include<iostream> #include<vector> usingnamespace std; int n, m, c; constint N = 2e5 + 10; int p[N], id[N], w[N]; structEdge { int v; int nxt; } edge[N * 2]; int head[N], ecnt; int lca[N]; voidadd(int u, int v){ edge[++ecnt].v = v; edge[ecnt].nxt = head[u]; head[u] = ecnt; } int fa[N][21], dep[N]; voidpre(int x,int f){ fa[x][0] = f; dep[x] = dep[f] + 1; for (int i = 1; i <= 19; i++) { fa[x][i] = fa[fa[x][i - 1]][i - 1]; } for (int i = head[x]; i; i = edge[i].nxt) { int v = edge[i].v; if (v == f) { continue; } pre(v, x); } } intgetLCA(int u, int v){ if (dep[u] < dep[v]) { swap(u, v); } for (int i = 19; i >= 0; i--) { if (dep[fa[u][i]] >= dep[v]) { u = fa[u][i]; } } if (u == v) { return u; } for (int i = 19; i >= 0; i--) { if (fa[u][i] != fa[v][i]) { u = fa[u][i]; v = fa[v][i]; } } return fa[u][0]; } vector<int> up[N], down[N]; int updep[N][21], ans[N]; int last[N]; voidqup(int x){ int p = last[w[x]]; last[w[x]] = dep[x]; updep[dep[x]][0] = last[w[x] + 1]; for (int i = 1; i <= 19; i++) { updep[dep[x]][i] = updep[updep[dep[x]][i - 1]][i - 1]; } for (auto d : up[x]) { int x = last[1]; if (x < dep[lca[d]]) { continue; } ++ans[d]; for (int i = 19; i >= 0; i--) { if (updep[x][i] >= dep[lca[d]]) { ans[d] += (1 << i); x = updep[x][i]; } } } for (int i = head[x]; i; i = edge[i].nxt) { int v = edge[i].v; if (v != fa[x][0]) { qup(v); } } last[w[x]] = p; } voidqdown(int x){ int p = last[w[x]]; last[w[x]] = dep[x]; updep[dep[x]][0] = last[w[x] - 1]; for (int i = 1; i <= 19; i++) { updep[dep[x]][i] = updep[updep[dep[x]][i - 1]][i - 1]; } for (auto d : down[x]) { int l = ans[d] + 1, r = c, res = ans[d]; while (l <= r) { int mid = (l + r) / 2; int x = last[mid], cnt = mid - ans[d] - 1; for (int i = 19; i >= 0; i--) { if ((1 << i) & cnt) { x = updep[x][i]; } } if (x > dep[lca[d]]) { res = mid; l = mid + 1; } else { r = mid - 1; } } ans[d] = res; } for (int i = head[x]; i; i = edge[i].nxt) { int v = edge[i].v; if (v != fa[x][0]) { qdown(v); } } last[w[x]] = p; } intmain(){ cin >> n >> m >> c; for (int i = 1; i <= c; i++) { cin >> p[i]; id[p[i]] = i; } for (int i = 1; i <= n; i++) { cin >> w[i]; w[i] = id[w[i]]; } for (int i = 1; i < n; i++) { int u, v; cin >> u >> v; add(u, v); add(v, u); } dep[1] = 1; pre(1, 0); int q; cin >> q; for (int i = 1; i <= q; i++) { int u, v; cin >> u >> v; lca[i] = getLCA(u, v); up[u].push_back(i); down[v].push_back(i); } memset(updep, 0, sizeof(updep)); qup(1); qdown(1); for (int i = 1; i <= q; i++) { cout << ans[i] << endl; } return0; }
#include<algorithm> #include<cstdio> #include<iostream> usingnamespace std; constint N = 13, M = 500; int n, m, S, a[N + 1], id[1 << N | 1]; longlong dp[(1 << N) + 1][N + 1][M + 1]; intlowbit(int x){ return x & (-x); } int mmax = -1, maxid; intmain(){ cin >> n >> m; S = (1 << n) - 1; for (int i = 1; i <= n; i++) { cin >> a[i]; if (a[i] > mmax) { mmax = a[i]; maxid = i; } id[1 << (i - 1)] = i; } for (int i = 1; i <= n; i++) { int v = n * (mmax - a[i] + (maxid < i)); if (v <= m) { dp[1 << (i - 1)][i][v] = 1; } } for (int i = 1; i < S; i++) { int cnt = __builtin_popcount(i); for (int t = i; t; t -= lowbit(t)) { for (int sum = 0; sum <= m; sum++) { int pos = id[lowbit(t)]; for (int j = 1; j <= n; ++j) { if ((i & (1 << (j - 1)))) { continue; } else { int v = sum + (n - cnt) * max(0, (pos < j) + a[pos] - a[j]); if (v <= m) { dp[i | (1 << (j - 1))][j][v] += dp[i][pos][sum]; } } } } } } longlong ans = 0; for (int i = 0; i <= m; i++) { for (int j = 1; j <= n; j++) { ans += dp[S][j][i]; } } cout << ans; return0; }
D2T3 支配
显然支配关系会构成一个树,假如我们通过奥妙重重的方法拿到了这个树
考虑加入边 (u,v) 的影响,可以发现若 x 的受支配集变化当且仅当 fax 的受支配集变化或者 fax 不支配 x
#include<iostream> #include<queue> usingnamespace std; constint N = 3005; structGraph { structEdge { int v; int nxt; } edge[N * 2]; int head[N], ecnt; voidadd(int u, int v){ edge[++ecnt].v = v; edge[ecnt].nxt = head[u]; head[u] = ecnt; } } G, rG; int n, m, q; bool dom[N][N], qaq[N][N]; int in[N], fa[N], id[N]; voidbuild(){ for (int i = 1; i <= n; i++) { dom[1][i] = 1; } for (int i = 2; i <= n; i++) { for (int j = 2; j <= n; j++) { dom[i][j] = 1; } queue<int> q; q.push(1); while (!q.empty()) { int x = q.front(); q.pop(); for (int _i = G.head[x]; _i; _i = G.edge[_i].nxt) { int v = G.edge[_i].v; if (dom[i][v] && (i != v)) { dom[i][v] = 0; q.push(v); } } } } for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { in[j] += dom[i][j]; } } queue<int> q; q.push(1); staticint que[N], head; que[++head] = 1; while (!q.empty()) { int x = q.front(); q.pop(); for (int i = 1; i <= n; i++) { if (dom[x][i]) { --in[i]; if (in[i] == 1) { fa[i] = x; q.push(i); que[++head] = i; } } } } for (int i = 1; i <= n; i++) { id[i] = que[i]; } for (int i = 2; i <= n; i++) { queue<int> q; q.push(i); qaq[i][i] = 1; while (!q.empty()) { int x = q.front(); q.pop(); for (int j = rG.head[x]; j; j = rG.edge[j].nxt) { int v = rG.edge[j].v; if (!qaq[i][v] && (v != fa[i])) { qaq[i][v] = 1; q.push(v); } } } } } intmain(){ cin >> n >> m >> q; for (int i = 1; i <= m; i++) { int u, v; scanf("%d%d", &u, &v); G.add(u, v); rG.add(v, u); } build(); while (q--) { staticbool vis[N]; int a, b; scanf("%d%d", &a, &b); int ans = 0; for (int i = 2; i <= n; i++) { vis[id[i]] = ((!dom[fa[id[i]]][a] && qaq[id[i]][b]) || (vis[fa[id[i]]])); ans += vis[id[i]]; } cout << ans << endl; } return0; }