关于一类偏序问题
对于一类依赖偏序关系计算答案的问题,由于我们只关注元素之间的大小关系,从而可以通过特殊的枚举方式来避免多种情况分类讨论。常见方法有:
-
:通过从小到大的方式依次考虑元素。 -
:通过拆成 或 的形式后,再从小到大考虑。 -
当然如果是二位偏序问题,还可以放到坐标系下进行讨论。
一些例题:
[模拟赛]dist
Statement:
给定一棵
Solution:
我们只关注路径上最小的一条边,于是按边权从小到大依次考虑边带来的贡献,然后分成两个连通块做。但这样太慢了,所以逆向的进行合并,用并查集维护即可。
qwq
#include<bits/stdc++.h> #pragma GCC optimize(3, "Ofast", "inline") #define int long long using namespace std; const int N = 1e6 + 10; int n, fa[N], siz[N], val[N]; struct Edge{ int u, v, w; }E[N]; bool cmp(struct Edge E1, struct Edge E2){ return E1.w > E2.w; } int findfa(int x){return fa[x] = (fa[x] == x) ? x : findfa(fa[x]);} void merge(int x, int y, int w){ int fx = findfa(x), fy = findfa(y); if(fx == fy) return; if(siz[fx] < siz[fy]) swap(fx, fy); val[fx] = max(val[fx] + siz[fy] * w, val[fy] + siz[fx] * w); fa[fy] = fx; siz[fx] += siz[fy]; } signed main(){ // freopen("dist3.in", "r", stdin); freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n; for(int i = 1; i <= n; i++) siz[i] = 1, fa[i] = i; for(int i = 1; i < n; i++) cin >> E[i].u >> E[i].v >> E[i].w; sort(E + 1, E + n, cmp); for(int i = 1; i < n; i++) merge(E[i].u, E[i].v, E[i].w); cout << val[findfa(1)]; return 0; }
[模拟赛]博弈游戏
Statement:
Solution:
令
注意到
-
:显然我们更新的是一些点的 ,那么注意到我们在从大到小枚举的过程中,最后一次更新到 时才会对 产生贡献,于是我们动态更行他的入度,当 的入度变为 时,就将 赋值为 。 -
:此时更新的是一些点的 ,只要 没有被更新过,那么 就是他的所有后继中最小的那个了。
拿队列更新就可以了。、
qwq
#include<bits/stdc++.h> #define pir pair<int, int> #pragma GCC optimize(3, "Ofast", "inline") using namespace std; const int N = 1e5 + 10; int n, m, out[N], f[N][2]; struct edges{ int v, next; }edges[N << 1]; int head[N], idx; void add_edge(int u, int v){ edges[++idx] = {v, head[u]}; head[u] = idx; } void solve(int rt){ queue<pir> Q; if(!f[rt][0]) Q.push(make_pair(rt, 0)), f[rt][0] = rt; if(!f[rt][1]) Q.push(make_pair(rt, 1)), f[rt][1] = rt; while(!Q.empty()){ int u = Q.front().first, id = Q.front().second; Q.pop(); // cout << u << " " << id << " " << f[u][id] << "\n"; for(int i = head[u]; i; i = edges[i].next){ int v = edges[i].v; if(id == 0 && (!f[v][1])) f[v][1] = rt, Q.push(make_pair(v, 1)); else if(id == 1){ out[v]--; if(!out[v]) f[v][0] = rt, Q.push(make_pair(v, 0)); } } } } signed main(){ // freopen("game.in", "r", stdin); // freopen("game.out", "w", stdout); ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> n >> m; for(int i = 1; i <= m; i++){ int x, y; cin >> x >> y; add_edge(y, x); out[x]++; } for(int i = n; i > 0; i--) solve(i); for(int i = 1; i <= n; i++) cout << f[i][1] << " "; return 0; }
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18416646
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步