当前位置: 首页 > news >正文

动态 DP 的应用:线段树维护卷积

xyd 模拟赛的题,感觉非常 Educational。

Description

给定一颗 \(n\) 个节点的树,每个节点有 \(a_i\) 个石子和权值 \(b_i\)
Alice 和 Bob 每次选定两个星球 \(u\)\(v\),游戏在 \(u\)\(v\) 间路径上的所有节点进行,Alice 先手。一次操作可以选择路径上的一个还有石子的节点,并取走任意一个石子,或取走任意两个相邻的石子。一次操作后,原本连续的一行石子可能会被分成两段独立的子游戏,取到最后一颗石子的玩家赢。
Bob 在游戏开始前,可以拿走路径上任意数量星球的石子。从第 \(i\) 个节点每拿一个石子,需要代价 \(b_i\)。修改后,剩下的石子会重新排成连续的一列。
Bob 希望通过预先的修改,使得在接下来的比赛中他拥有必胜策略,他希望你能计算出达成这一目标所需的最小总代价。
有时 \(a_i\)\(b_i\) 可能会变化。请维护修改并回答询问。

\(n,q \le 5 \times 10^4,a_i,b_i \le 10^9\)

Solution

对 SG 函数打表,发现 SG 函数从 \(72\) 往后出现循环,循环节为 \(12\)。但循环本身并没有好的规律。

注意到 SG 函数异或后的可能值不超过 \(16\)考虑 DP。把链拍到序列上,定义 \(f_{i,j}\) 表示位置 \(i\) 最终异或和为 \(j\) 的答案,则 \(f_{i,j}=\min{f_{i-1,k}+v_{i,j \oplus k}}\)\(v_{i,j}\) 表示把 \(i\) 的 SG 值变为 \(j\) 的最小代价。

发现各位间相互独立,且每次转移都是 \((\min,+)\) 卷积的形式,可以快速合并。因此对每个位置维护好 \(v\) 就可以在链上一路合并上去再合并下来。不难联想到同样的线段树维护矩阵,用线段树维护卷积过程即可。时间复杂度 \(O(q V^2 \log^2 n)\),其中 \(V=16\)

Code

#include<bits/stdc++.h>
#define int long long
#define rep(i,a,b) for(int i=(a);i<=(int)(b);i++)
#define pb emplace_back
#define inf 1e18
#define lb(x) ((x) & -(x))
using namespace std;
const int N=1e5+10;
const int vl[73]={0,1,2,3,1,4,3,2,1,4,2,6,4,1,2,7,1,4,3,2,1,4,6,7,4,1,2,8,5,4,7,2,1,8,6,7,4,1,2,3,1,4,7,2,1,8,2,7,4,1,2,8,1,4,7,2,1,4,2,7,4,1,2,8,1,4,7,2,1,8,6,7,4};
const int gl[12]={4,1,2,8,1,4,7,2,1,8,2,7};
int sg(int x){return (x<=72)?vl[x]:gl[x%12];}
int to[100][20],val[12][20];int n,q,a[N],b[N];
vector<int> G[N];int fa[N],dep[N],sz[N],hs[N],pre[N];
int idx,dfn[N],rnk[N],top[N];
void dfs1(int x,int f)
{pre[x]=pre[f]^sg(a[x]);fa[x]=f,dep[x]=dep[f]+1,sz[x]=1,hs[x]=-1;for(auto y:G[x]){if(y==f) continue;dfs1(y,x);sz[x]+=sz[y];if(hs[x]==-1||sz[hs[x]]<sz[y]) hs[x]=y;}
}
void dfs2(int x,int t)
{dfn[x]=++idx,rnk[idx]=x,top[x]=t;if(hs[x]==-1) return;dfs2(hs[x],t);for(auto y:G[x]) if(y!=fa[x]&&y!=hs[x]) dfs2(y,y);
}struct node  // 重载卷积
{int f[1<<4];node(){rep(i,0,15) f[i]=inf;}void clear(){rep(i,0,15) f[i]=inf;}node operator *(const node &x) const{node res;rep(i,0,15) rep(j,0,15) res.f[i^j]=min(res.f[i^j],f[i]+x.f[j]);return res;}
}I;  // I 是单位元
void print(const node &x)
{rep(i,0,15) cout<<x.f[i]<<" ";cout<<"\n";
}
void get(node &t,int x,int y)
{t.clear();if(x<=84){rep(i,0,15) if(to[x][i]!=inf) t.f[i]=min(t.f[i],to[x][i]*y);}elserep(i,0,15){if(val[x%12][i]!=inf) t.f[i]=min(t.f[i],val[x%12][i]*y);if(to[84][i]!=inf) t.f[i]=min(t.f[i],(to[84][i]+x-84)*y);}
}
#define lc x<<1
#define rc x<<1|1
#define mid ((l+r)>>1)
struct segtree
{node t[N<<2];void up(int x){t[x]=t[lc]*t[rc];}void build(int x,int l,int r){if(l==r) return get(t[x],a[rnk[l]],b[rnk[l]]);build(lc,l,mid),build(rc,mid+1,r);up(x);}void update(int x,int l,int r,int p,int a,int b){if(l==r) return get(t[x],a,b);if(p<=mid) update(lc,l,mid,p,a,b);else update(rc,mid+1,r,p,a,b);up(x);}node query(int x,int l,int r,int L,int R){if(L<=l&&r<=R) return t[x];node res=I;if(L<=mid) res=res*query(lc,l,mid,L,R);if(mid+1<=R) res=res*query(rc,mid+1,r,L,R);return res;}
}tr;int query(int x,int y)
{node res=I;while(top[x]!=top[y]){if(dep[top[x]]<dep[top[y]]) swap(x,y);res=res*tr.query(1,1,n,dfn[top[x]],dfn[x]);x=fa[top[x]];}if(dfn[x]>dfn[y]) swap(x,y);res=res*tr.query(1,1,n,dfn[x],dfn[y]);return res.f[0];
}
signed main()
{freopen("interstellar.in","r",stdin);freopen("interstellar.out","w",stdout);ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);I.f[0]=0;rep(i,1,84){rep(j,0,15) to[i][j]=inf;rep(j,0,i) to[i][sg(j)]=i-j;}rep(i,0,11){rep(j,0,15) val[i][j]=inf;rep(j,i+1,11) val[i][gl[j]]=12-j+i;rep(j,0,i) val[i][gl[j]]=i-j;}cin>>n;rep(i,1,n) cin>>a[i];rep(i,1,n) cin>>b[i];rep(i,1,n-1){int u,v; cin>>u>>v;G[u].pb(v),G[v].pb(u);}dfs1(1,0),dfs2(1,1);tr.build(1,1,n);cin>>q;rep(_,1,q){int opt,x,y,z;cin>>opt>>x>>y;if(opt==1) cin>>z,tr.update(1,1,n,dfn[x],y,z);else cout<<query(x,y)<<"\n";}return 0;
}
http://www.jsqmd.com/news/746492/

相关文章:

  • 别再让实验‘打架’了!用Google分层分流模型,5步搞定AB测试流量分配
  • VL53L0X的三种测量模式怎么选?从扫地机避障到手势识别实战解析
  • 微信立减金回收全解析,资深行业人士揭秘变现法则 - 京顺回收
  • VAPO框架:提升视觉语言模型细粒度感知的实践指南
  • OBS高级计时器完整指南:6种专业模式让直播时间管理变得简单
  • 从冷启动到热启动:深入解读Honeywell EPKS CEE重启机制与工程实践选择
  • 告别网页版!手把手教你用GitHub源码在Ubuntu 22.04上编译安装B站Linux客户端
  • 工商注册、财税代理、资质办理哪家强?深圳5家机构服务力对比 - 小征每日分享
  • 2026.5 AI终极评测:GPT-5.5登顶,Claude 4.7守王座,国产谁争锋?
  • DIY 3D打印机电源与散热改造:从12V升级24V热床,告别加热慢
  • 手把手教你用国产BR3109芯片搭建JESD204B数据链路(附FPGA IP核配置避坑指南)
  • AI模型越狱攻防实战:从安全机制到社区驱动的漏洞追踪
  • 金蝶K/3 Cloud AI集成:基于MCP协议构建企业ERP智能体网关
  • DDP、FSDP、DeepSpeed到底怎么选?2024企业级分布式训练框架选型决策树,一文定乾坤
  • 玩机高手进阶:深入浅出解析高通EDL模式,除了`adb reboot edl`还能怎么进?
  • 不只是编译:用LiDAR_IMU_Init完成一次真实的激光雷达与IMU外参标定实战
  • 别再死记硬背了!AutoSar COM模块的7个性能优化点,实战配置避坑指南
  • Vivado单端口RAM IP核的三种读写模式(写优先/读优先/不变)到底该怎么选?附仿真对比
  • 从模块例化到IP复用:手把手教你玩转Verilog的parameter参数传递(含defparam与#()两种方式详解)
  • Qt6项目实战:用QScopedPointer重构一段‘祖传’代码,看看能省下多少行delete
  • FPGA片上学习技术:实现纳秒级自适应机器学习
  • Go语言代理扫描器设计:插件化架构与身份认证实践
  • LoRA+QLoRA+Adapter三重配置冲突诊断:Python微调中87%OOM错误的根源定位指南
  • RTK定位中的RTCM3.2:为什么你的无人机/农机需要它?从协议到应用的避坑指南
  • WebPlotDigitizer完整指南:如何从图表图像中高效提取数据
  • 多模态生成模型评估:MMGR基准设计与实践
  • 多智能体药物发现系统MADD的设计与实践
  • 告别通信混乱!深入理解AUTOSAR ComM如何协调Nm和SM实现高效网络管理
  • 告别手动拖拽!用Python+ddddocr搞定滑块验证码的完整实战(附轨迹模拟源码)
  • Claude Opus 4.7 升级引发“中文税”讨论:分词器差异如何影响模型成本与理解?