Codeforces Gym 103446H. Life is a Game
2021/12/6 6:19:05
本文主要是介绍Codeforces Gym 103446H. Life is a Game,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Codeforces Gym 103446H. Life is a Game
容易注意到, 对于每一次询问, 所有经过的节点必定组成一个连通块, 而且所有经过的边必定是原图最小生成树上的包含该连通块的边集. 基于这个性质, 可以想到两种解法:
解法一
对于一个询问, 最朴素的求解办法就是按边权从小到大枚举每一条边, 如果这一条边在当前询问的连通块上, 且当前询问可以通过该边, 那么就将当前询问的连通块改为这条边所连两个连通块的并. 最后该询问的答案就是其当前连通块内所有点权值的和加上初始值. 该做法时间复杂度为 \(\mathcal O(n^2)\) .
考虑优化. 容易发现, 对于所有询问, 都必须经过的步骤是按边权从小到大枚举每一条边; 而它们的不同之处就是判定每个询问是否可以经过当前枚举的边. 又注意到在同一连通块内的所有询问的答案只和询问初始值有关, 于是可以考虑启发式合并. 对于每一个连通块, 用一个堆来维护有哪些询问在当前连通块中. 枚举边 \(e\,(u,\,v,\,w)\) 合并时先将 \(u,v\) 连通块内所有不能通过边 \(e\) 的询问处理掉, 并将它们在堆中删除后, 将剩余 \(u,v\) 所在连通块的堆按启发式合并. 每一次合并的复杂度为 \(\mathcal O(\min\{|S_u|,\,|S_v|\})\) , 因此总时间复杂度就是 \(\mathcal O(n\log n)\) .
参考代码 ( by qyw )
#include<bits/stdc++.h> #define pii pair<int,int> #define fi first #define se second using namespace std; const int N=100005; long long INF=0x3f3f3f3f3f3f3f3f; int n,m,q,a[N]; int fa[N],sz[N]; long long rr[N],sum[N]; struct edge{int u,v,w;}e[N]; priority_queue<pii> pq[N]; bool cmp(edge a,edge b){return a.w<b.w;} int findfa(int x){return x==fa[x]?x:fa[x]=findfa(fa[x]);} void dlpq(int x,long long w) { while(!pq[x].empty()) { pii u=pq[x].top(); if(-u.fi+sum[x]>=w) return; rr[u.se]=-u.fi+sum[x],pq[x].pop(); } } void mgpq(int x,int y,int w) { while(!pq[x].empty()) { pii u=pq[x].top(); pq[x].pop(); pq[y].push(u); } } void merge(int x,int y,int w) { int fx=findfa(x),fy=findfa(y); if(fx==fy) return; dlpq(fx,w),dlpq(fy,w); if(pq[fx].size()>pq[fy].size()) swap(fx,fy); mgpq(fx,fy,w); fa[fx]=fy,sum[fy]+=sum[fx]; } void solve() { sort(e+1,e+m+1,cmp); for(int i=1;i<=n;i++) fa[i]=i,sum[i]=a[i]; for(int i=1;i<=m;i++) merge(e[i].u,e[i].v,e[i].w); int ff=findfa(1); dlpq(ff,INF); for(int i=1;i<=q;i++) printf("%d\n",rr[i]); } int main() { scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w); for(int i=1;i<=q;i++) { int x,y; scanf("%d%d",&x,&y); pq[x].push(pii{-y,i}); } solve(); }
解法二
考虑按边权从小到大构造原图的 \(\text{Kruskal}\) 重构树.
每一次询问在重构树上从叶节点开始暴力跳父亲, 直到找到第一条不能通过的边 (即该边下面的子树点权值和加上初始值小于该边权值). 这样做的正确性显然, 时间复杂度为 \(\mathcal O(n^2)\) .
注意到上述暴力跳父亲的过程可以用树上倍增优化. 于是就结束了, 时间复杂度为 \(\mathcal O(n\log n)\) .
参考代码
#include <bits/stdc++.h> using namespace std; static constexpr int Maxn = 2e5 + 5, LOG = 19; static constexpr int64_t inf = 0x3f3f3f3f3f3f3f3f; int n, m, q, nc; int64_t a[Maxn]; struct Edge { int u, v; int64_t w; Edge() = default; Edge(int u, int v, int64_t w) : u(u), v(v), w(w) { } friend bool operator < (const Edge &lhs, const Edge &rhs) { return lhs.w < rhs.w; } } e[Maxn]; int fa[Maxn]; int fnd(int x) { return fa[x] == x ? x : fa[x] = fnd(fa[x]); } // fnd vector<int> g[Maxn]; int64_t b[Maxn], sa[Maxn]; int64_t c[LOG][Maxn]; int par[LOG][Maxn]; void dfs(int u, int fa) { sa[u] = (u > n ? 0 : a[u]); par[0][u] = fa; for (int j = 1; j < LOG; ++j) par[j][u] = par[j - 1][par[j - 1][u]]; for (const int &v: g[u]) dfs(v, u), sa[u] += sa[v]; c[0][u] = (u == nc ? -inf : sa[u] - b[fa]); } // dfs int main(void) { scanf("%d%d%d", &n, &m, &q); for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]); for (int i = 1; i <= m; ++i) scanf("%d%d%lld", &e[i].u, &e[i].v, &e[i].w); sort(e + 1, e + m + 1); for (int i = 1; i <= n; ++i) fa[i] = i; nc = n; for (int i = 1; i <= m; ++i) { int u = e[i].u, v = e[i].v; int64_t w = e[i].w; int fu = fnd(u), fv = fnd(v); if (fu != fv) { ++nc, fa[nc] = nc; b[nc] = w; fa[fu] = nc, fa[fv] = nc; g[nc].push_back(fu); g[nc].push_back(fv); } } memset(c, inf, sizeof(c)); dfs(nc, 0); for (int j = 1; j < LOG; ++j) for (int i = 1; i <= nc; ++i) c[j][i] = min(c[j - 1][i], c[j - 1][par[j - 1][i]]); while (q--) { int x; int64_t w; scanf("%d%lld", &x, &w); if (b[par[0][x]] > w + a[x]) { printf("%lld\n", w + a[x]); } else { int u = x; for (int j = LOG - 1; j >= 0; --j) if (w + c[j][u] >= 0) u = par[j][u]; printf("%lld\n", sa[u] + w); } } exit(EXIT_SUCCESS); } // main
这篇关于Codeforces Gym 103446H. Life is a Game的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-06PingCAP 连续两年入选 Gartner 云数据库管理系统魔力象限“荣誉提及”
- 2025-01-05Easysearch 可搜索快照功能,看这篇就够了
- 2025-01-04BOT+EPC模式在基础设施项目中的应用与优势
- 2025-01-03用LangChain构建会检索和搜索的智能聊天机器人指南
- 2025-01-03图像文字理解,OCR、大模型还是多模态模型?PalliGema2在QLoRA技术上的微调与应用
- 2025-01-03混合搜索:用LanceDB实现语义和关键词结合的搜索技术(应用于实际项目)
- 2025-01-03停止思考数据管道,开始构建数据平台:介绍Analytics Engineering Framework
- 2025-01-03如果 Azure-Samples/aks-store-demo 使用了 Score 会怎样?
- 2025-01-03Apache Flink概述:实时数据处理的利器
- 2025-01-01使用 SVN合并操作时,怎么解决冲突的情况?-icode9专业技术文章分享