挑战
最后发现就是分块大暴力,要是有更有意思的解法就好了(不过这个信息本来就没有优秀的合并方式,或者用一种二位在线偏序结构倒是可以解决这个问题)。
// challenge.cpp #pragma GCC optimize("O2") #include <bits/stdc++.h> #define ll long long using namespace std; const int MAX_N = 1e5 + 200; const unsigned MAGIC_NUM = 4294967295u; ll ai[MAX_N], wi[MAX_N], n, q, block_siz, block_tot, lft[MAX_N]; pair<ll, int> tmp[MAX_N]; ll pre[MAX_N], tree[MAX_N]; int lowbit(int x) { return x & (-x); } void update(int x, ll d) { for (; x <= n; x += lowbit(x)) tree[x] += d; } ll query(int x) { ll ans = 0; for (; x; x -= lowbit(x)) ans += tree[x]; return ans; } unsigned xnor(unsigned a, unsigned b) { return ~((a & MAGIC_NUM) ^ (b & MAGIC_NUM)); } void rebuild(int id) { for (int i = lft[id]; i <= lft[id + 1] - 1; i++) tmp[i] = make_pair(wi[i], i); sort(tmp + lft[id], tmp + lft[id + 1]); pre[lft[id]] = wi[tmp[lft[id]].second] * ai[tmp[lft[id]].second]; for (int i = lft[id] + 1; i <= lft[id + 1] - 1; i++) pre[i] = pre[i - 1] + wi[tmp[i].second] * ai[tmp[i].second]; } int main() { scanf("%lld%lld", &n, &q); block_siz = sqrt(n), block_tot = (n + block_siz - 1) / block_siz; lft[1] = 1, lft[block_tot + 1] = n + 1; for (int i = 2; i <= block_tot; i++) lft[i] = lft[i - 1] + block_siz; for (int i = 1; i <= n; i++) scanf("%lld", &ai[i]), update(i, ai[i]); for (int i = 1; i <= n; i++) scanf("%lld", &wi[i]); for (int i = 1; i <= block_tot; i++) rebuild(i); while (q--) { ll op, x, y, z; scanf("%lld%lld%lld", &op, &x, &y); if (op == 1) { scanf("%lld", &z); unsigned ans = 0, pans = query(y) - query(x - 1); int xid = (x + block_siz - 1) / block_siz, yid = (y + block_siz - 1) / block_siz; if (xid != yid) { for (int i = xid + 1; i <= yid - 1; i++) { int pos = lower_bound(tmp + lft[i], tmp + lft[i + 1], make_pair(z + 1, 0)) - tmp - 1; ans += pos >= lft[i] ? pre[pos] : 0; } for (int i = x; i <= lft[xid + 1] - 1; i++) if (wi[i] <= z) ans += wi[i] * ai[i]; for (int i = lft[yid]; i <= y; i++) if (wi[i] <= z) ans += wi[i] * ai[i]; } else for (int i = x; i <= y; i++) if (wi[i] <= z) ans += wi[i] * ai[i]; printf("%u\n", xnor(ans, pans)); } else if (op == 2) { update(x, -ai[x]), ai[x] = y; rebuild((x + block_siz - 1) / block_siz); update(x, ai[x]); } else { wi[x] = y; rebuild((x + block_siz - 1) / block_siz); } } return 0; }
CF9E
真的暴力,本来以为是\(O(n^2 \log n)\)的大暴力,忘记了 BFS 可以做到更优(因为队列中的距离单调)。
@@ -0,0 +1,82 @@ // CF59E.cpp #include <bits/stdc++.h> #define pr pair<int, int> using namespace std; const int MAX_N = 3010, MAX_M = 20202; int head[MAX_N], current, n, m, k; int upward[MAX_N][MAX_N], dist[MAX_N][MAX_N], tmp[MAX_N]; vector<int> vecs[MAX_N][MAX_N]; struct edge { int to, nxt; } edges[MAX_M << 1]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } bool check(int a, int b, int c) { for (int i = 0, siz = vecs[a][b].size(); i < siz; i++) if (vecs[a][b][i] == c) return false; return true; } void writeAns(int pre) { printf("%d\n1 ", dist[pre][n]); int pt = n, tot = 0; int fat = n; /* while (pt != 1) { tmp[++tot] = pt; int tp = pre, pre = upward[pre][pt], pt = tp; } */ while (fat != 1) { tmp[++tot] = fat; int tp = pre; pre = upward[pre][fat]; fat = tp; } for (int i = tot; i >= 1; i--) printf("%d ", tmp[i]); } void bfs() { queue<pr> q; q.push(make_pair(0, 1)); while (!q.empty()) { int pre = q.front().first, u = q.front().second; q.pop(); if (u == n) writeAns(pre), exit(0); for (int i = head[u]; i != -1; i = edges[i].nxt) if (!dist[u][edges[i].to] && check(pre, u, edges[i].to)) upward[u][edges[i].to] = pre, dist[u][edges[i].to] = dist[pre][u] + 1, q.push(make_pair(u, edges[i].to)); } } int main() { memset(head, -1, sizeof(head)); scanf("%d%d%d", &n, &m, &k); for (int i = 1, u, v; i <= m; i++) scanf("%d%d", &u, &v), addpath(u, v), addpath(v, u); for (int i = 1, x, y, z; i <= k; i++) scanf("%d%d%d", &x, &y, &z), vecs[x][y].push_back(z); bfs(); puts("-1"); return 0; }
CF1244D
刚开始觉得挺复杂,后面发现多数情况都可以被判作无解:除了一条链的情况,其他都可以被认为是无解的,这个很容易证明。所以,搞 6 次就可以拿到解。
// CF1244D.cpp #include <bits/stdc++.h> #define int long long using namespace std; const int MAX_N = 1e5 + 200; int head[MAX_N], current, n, color[4][MAX_N], dp[MAX_N], deg[MAX_N], answer[MAX_N]; struct edge { int to, nxt; } edges[MAX_N << 1]; void addpath(int src, int dst) { edges[current].to = dst, edges[current].nxt = head[src]; head[src] = current++; } void dfs(int u, int fa, int A, int B) { dp[u] = 0; for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].to != fa) { dfs(edges[i].to, u, B, A ^ B); dp[u] += dp[edges[i].to]; } dp[u] += color[A ^ B][u]; } void getAns(int u, int fa, int A, int B) { answer[u] = A ^ B; for (int i = head[u]; i != -1; i = edges[i].nxt) if (edges[i].to != fa) getAns(edges[i].to, u, B, A ^ B); } signed main() { memset(head, -1, sizeof(head)); scanf("%lld", &n); for (int i = 1; i <= 3; i++) for (int j = 1; j <= n; j++) scanf("%lld", &color[i][j]); for (int i = 1, u, v; i < n; i++) scanf("%lld%lld", &u, &v), deg[u]++, deg[v]++, addpath(u, v), addpath(v, u); int pt = 0; bool flag = false; for (int i = 1; i <= n; i++) flag |= deg[i] > 2, pt = (deg[i] == 1 ? i : pt); if (flag) puts("-1"), exit(0); int ans = 1e18, oA, oB; for (int A = 1; A <= 3; A++) for (int B = 1; B <= 3; B++) if (A != B) { dfs(pt, 0, A, B); if (dp[pt] < ans) oA = A, oB = B, ans = dp[pt]; } getAns(pt, 0, oA, oB); printf("%lld\n", ans); for (int i = 1; i <= n; i++) printf("%lld ", answer[i]); return 0; }