P7246 手势密码
Statement:
有一棵
问至少需要多少次操作,使树上所有点的点权恰好变为
Solution:
对于这样的问题不好入手,则优先考虑转化。
首先将第
考虑最坏的情况,显然是需要
-
找到一组小点,且这组小点对应的大点组成一条简单路径。
-
这些小点没有任何一对是兄弟点。
-
每个点至多连两条边。
最后消掉的贡献
我们考虑递归解决此问题,假设我们已经到了点
从而不难设计出一个树形
显然
code:
qwq
#include<bits/stdc++.h> #define int long long using namespace std; const int N = 3e6 + 10; int n, a[N], f[N], ans; struct edge{ 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; } namespace Generate{ int n,seed; static const int mod=1e9; int Rand(int x){ seed=(1ll*seed*0x66CCF+19260817ll)%x+1; seed=(1ll*seed*0x77CCF+20060428ll)%x+1; seed=(1ll*seed*0x88CCF+12345678ll)%x+1; seed=(1ll*seed*0x33CCCCFF+10086001ll)%x+1; return seed; } void RS(){ //你需要传入三个参数,分别表示点权,一条边的两个端点 int cnt=0; for(int i=1;i<=n;i++)a[i]=Rand(mod); for(int i=2;i<=n;i++){ int fa=Rand(i-1); cnt++; add_edge(fa, i); add_edge(i, fa); } } }; void dfs(int u, int fa){ int sum = 0; for(int i = head[u]; i; i = edges[i].next){ int v = edges[i].v; if(v == fa) continue; dfs(v, u); f[u] += f[v]; sum += min(a[u], a[v]); } f[u] += min(a[u] * 2, sum); a[u] -= min(a[u], max(0ll, sum - a[u])); } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int opt; cin >> opt; if(opt == 1){ cin >> n; for(int i = 1; i <= n; i++) cin >> a[i], ans += a[i]; for(int i = 1; i < n; i++){ int x, y; cin >> x >> y; add_edge(x, y); add_edge(y, x); } } else{ cin >> Generate::seed >> n; Generate::n = n;//记得赋值 Generate::RS(); //开始工作 for(int i = 1; i <= n; i++) ans += a[i]; } dfs(1, 0); cout << ans - f[1]; return 0; }
本文作者:Little_corn
本文链接:https://www.cnblogs.com/little-corn/p/18248596
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步