省选测试46


又倒第一了,流汗黄豆稳了

A 签到题#

题目大意 : 每个点有个到最后的单调栈,会有修改和询问

  • 转换一下题意,找到后面第一个比自己大的点向自己连边,就形成了个森林,建个超级源点,就成了颗树

  • 修改操作就变成了把x和x的一级儿子都加上v,询问操作变成了查找x,y路径上的和,如果x,y的lca是x或y,那么还要再加上fa[lca]的值

  • 询问好搞,树剖就行,问题是如何修改x和x的所有儿子。由于有树剖,可以考虑只修改x和x的重儿子,给x记一个标记,然后跳轻边的时候加上fa[tp]的标记

  • 最后一条链如果链顶是tp的话,还得加上fa[tp]的标记,lca是xy的要特殊处理一下

Code#

Show Code
Copy
#include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int N = 2e5 + 5; int read(int x = 0, int f = 1, char c = getchar()) { for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0'; return x * f; } struct Edge { int n, t; }e[N]; int h[N], edc; void Add(int x, int y) { e[++edc] = (Edge) {h[x], y}; h[x] = edc; } ll t[N], s[N], ans; int n, m, a[N], stk[N], top, dep[N], sz[N], son[N], fa[N], tp[N], dfn[N], dfc; void Dfs(int x) { dep[x] = dep[fa[x]] + 1; sz[x] = 1; for (int i = h[x], y; i; i = e[i].n) { if ((y = e[i].t) == fa[x]) continue; fa[y] = x; Dfs(y); sz[x] += sz[y]; if (sz[son[x]] < sz[y]) son[x] = y; } } void Dfs(int x, int top) { tp[x] = top; dfn[x] = ++dfc; if (son[x]) Dfs(son[x], top); for (int i = h[x], y; i; i = e[i].n) if ((y = e[i].t) != fa[x] && y != son[x]) Dfs(y, y); } void Modify(int x, int w) { for (; x <= dfc; x += x & -x) t[x] += w; } ll Ask(int l, int r, ll ans = 0) { for (; r; r -= r & -r) ans += t[r]; for (l--; l; l -= l & -l) ans -= t[l]; return ans; } int main() { freopen("set.in", "r", stdin); freopen("set.out", "w", stdout); n = read(); m = read(); for (int i = 1; i <= n; ++i) a[i] = read(); stk[++top] = n + 1; a[n+1] = 1e9; for (int i = n; i >= 1; --i) { while (top && a[i] >= a[stk[top]]) top--; Add(stk[top], i); stk[++top] = i; } Dfs(n + 1); Dfs(n + 1, n + 1); for (int i = 1; i <= n; ++i) Modify(dfn[i], read()); while (m--) { int od = read(), x = read(), y = read(); ans = 0; if (od == 1) { Modify(dfn[x], y); s[x] += y; if (son[x]) Modify(dfn[son[x]], y); } else { int tmp = dep[x] < dep[y] ? x : y; while (tp[x] != tp[y]) { if (dep[tp[x]] < dep[tp[y]]) swap(x, y); ans += Ask(dfn[tp[x]], dfn[x]); x = fa[tp[x]]; ans += s[x]; } if (dfn[x] > dfn[y]) swap(x, y); if (x == n + 1 || (x == tmp && fa[x] == n + 1)) { puts("?"); continue; } ans += Ask(dfn[x], dfn[y]); if (x == tp[x]) ans += s[fa[x]]; if (x == tmp) { x = fa[tmp]; ans += Ask(dfn[x], dfn[x]); if (x == tp[x]) ans += s[fa[x]]; } printf("%lld\n", ans); } } return 0; }

B 蓝超巨星 (Unaccepted)#

题目大意 :

Code#

Show Code
Copy

C 秘密行动#

题目大意 : 每个位置的每个可选的质数有选和不算的代价,还有一些限制,两个位置选择某个质数的状态不同则还有个代价,问最小代价积

  • 除了我大概都能看出来是网络流吧。

  • 取对数可以做到把乘转换成加,就成了求最小代价和

  • s向每个位置的每个质数连选的代价,质数向t连不选的代价,限制的话就两个质数连双向边,流量为差异代价,然后跑最小割就行

  • 如果写Dinic是return的是lim-sum,那开始传进去的lim不能太大

Code#

Show Code
Copy
#include <cmath> #include <cstdio> #include <cstring> #include <algorithm> #define double long double using namespace std; const int N = 505; int read(int x = 0, int f = 1, char c = getchar()) { for (; c < '0' || c > '9'; c = getchar()) if (c == '-') f = -1; for (; c >='0' && c <='9'; c = getchar()) x = x * 10 + c - '0'; return x * f; } struct Edge { int n, t; double f; }e[N*2]; int h[N], edc = 1, tmp[N]; void Add(int x, int y, double d) { e[++edc] = (Edge) {h[x], y, d}; h[x] = edc; e[++edc] = (Edge) {h[y], x, 0}; h[y] = edc; } double f[N], ans; int n, m, id[N][N], s, t, idc, dep[N], q[N]; bool Bfs() { memset(dep + 1, 0, t * 4); memcpy(h + 1, tmp + 1, t * 4); int l = 1, r = 1; q[1] = s; dep[s] = 1; while (l <= r) { int x = q[l++]; for (int i = h[x], y; i; i = e[i].n) { if (!e[i].f || dep[y=e[i].t]) continue; dep[y] = dep[x] + 1; q[++r] = y; if (y == t) return 1; } } return 0; } double Dinic(int x, double lim) { if (x == t) return lim; double sum = 0; for (int i = h[x]; i && lim; i = e[i].n) { int y = e[i].t; h[x] = i; if (!e[i].f || dep[y] != dep[x] + 1) continue; double f = Dinic(y, min(lim, e[i].f)); lim -= f; sum += f; e[i].f -= f; e[i^1].f += f; } if (!sum) dep[x] = 0; return sum; } int main() { freopen("secret.in", "r", stdin); freopen("secret.out", "w", stdout); n = read(); m = read(); for (int i = 1; i <= n; ++i) for (int j = 1; j <= 10; ++j) id[i][j] = ++idc; s = ++idc, t = s + 1; for (int i = 1, x; i <= 10; ++i) read(), scanf("%Lf", &f[i]); for (int i = 1; i <= n; ++i) { double x; for (int j = 1; j <= 10; ++j) scanf("%Lf", &x), Add(s, id[i][j], log2(x)); for (int j = 1; j <= 10; ++j) scanf("%Lf", &x), Add(id[i][j], t, log2(x)); } while (m--) { int x = read(), y = read(), z = read(); Add(id[x][z], id[y][z], log2(f[z])); Add(id[y][z], id[x][z], log2(f[z])); } memcpy(tmp + 1, h + 1, t * 4); while (Bfs()) ans += Dinic(s, 1e18); printf("%.10Lf\n", pow(2, ans)); return 0; }
posted @   Shawk  阅读(33)  评论(0)    收藏  举报
编辑推荐:
· 从零实现富文本编辑器#3-基于Delta的线性数据结构模型
· 记一次 .NET某旅行社酒店管理系统 卡死分析
· 长文讲解 MCP 和案例实战
· Hangfire Redis 实现秒级定时任务,使用 CQRS 实现动态执行代码
· Android编译时动态插入代码原理与实践
阅读排行:
· 使用TypeScript开发微信小程序(云开发)-入门篇
· 没几个人需要了解的JDK知识,我却花了3天时间研究
· 定时任务稳定性解决方案-healthchecks监控系统
· 在SqlSugar的开发框架中增加对低代码EAV模型(实体-属性-值)的WebAPI实现支持
· .NET Core中的配置Configuration实战
点击右上角即可分享
微信分享提示
CONTENTS