P5360

news/2025/1/9 21:04:55/文章来源:https://www.cnblogs.com/Forever1507/p/18662898

有点牛的题。

一个可能比较前置的技巧是 LCT 维护 MST 的方法,具体来说就是加边的时候,如果两边原本就是连通的,那么就把路径上的最大边权拿出来和要加的边进行比较,选择更优的那一个。这个技巧启示我们,在 MST 中只有任意两点的路径的最大边权是重要的,并且两张图的 MST 是支持进行合并的。

所以说,一个基本的思路是预处理出所有前缀和后缀对应的 MST 然后在查询的时候进行合并,但是总的点数是 \(n^2m\) 的,显然无法通过。

但是同时我们还注意到一个性质:这张图是一个网格图。这也就意味着,一个前缀/后缀形成的最小生成树,第 \(i\) 列和第 \(i+2\) 列的点是完全没有连边的。所以对于前缀/后缀的最小生成树,只有第一列和最后一列的点是重要的,那这不就是虚树吗?于是有一个朴素的做法,大力维护每个前缀/后缀的虚树然后在最后进行合并就可以了。

但是事实上这个虚树是不用真正建出来的,有一种基于并查集的更加方便的做法。具体来说,我们假设已经知道了前 \(i-1\) 列形成的 MST,我们现在要加到第 \(i\) 列,显然我们应该直接把原本两棵 MST 的边与连接两边的边一起做 Kruskal,但是为了控制点数,在这个过程中我们不希望第 \(i-1\) 列的点出现在新的 MST 中,所以并查集合并的时候,如果有一个集合里没有任何一个第一列或第 \(m\) 列的点,那么他就是不需要真正加入新 MST 中的边。但是它已经确定加入了贡献里且不再会被踢出,所以我们需要把它的边权累加进答案,然后把父亲指向有第一列或第 \(m\) 列的点的集合。否则,可以证明直接连接两个集合的祖先节点是等价的,然后把这条边加入新的边集即可。

具体来说,因为 MST 中只关心任意两点的路径的最大边权,且在 Kruskal 的过程中这条边一定是最大的,所以在两个集合中无论怎么连都能够保证路径的最大边权,所以起到的效果是等价的。

所以我们可以直接用并查集维护前后缀的 MST,询问时暴力合并即可 。

#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
namespace IN{const int Q = 1000000;#define getc() (p1==p2&&(p2=(p1=buf)+inbuf->sgetn(buf,Q),p1==p2)?EOF:*p1++)char buf[Q],*p1,*p2;template<typename T>inline bool read(T &x) {static std::streambuf *inbuf=cin.rdbuf();x=0;register int f=0,flag=false;register char ch=getc();while(!isdigit(ch)){if (ch=='-') f=1;ch=getc();}if(isdigit(ch)) x=x*10+ch-'0',ch=getc(),flag=true;while(isdigit(ch)) {x=x*10+ch-48;ch=getc();}x=f?-x:x;return flag;}template<typename T,typename ...Args>inline bool read(T& a,Args& ...args) {return read(a)&&read(args...);}#undef getc
}
using namespace IN;
const int N=105,M=10005;
int n,m,q,r[N][M],c[N][M];
unsigned int SA, SB, SC;int lim;
int getweight() {SA ^= SA << 16;SA ^= SA >> 5;SA ^= SA << 1;unsigned int t = SA;SA = SB;SB = SC;SC ^= t ^ SA;return SC % lim + 1;
}
void gen() {scanf("%d%d%u%u%u%d", &n, &m, &SA, &SB, &SC, &lim);int i, j, w;for(i = 1; i <= n; i++)for(j = 1; j <= m; j++) {// w = getweight();// if (j < m) {//     addedge(i, j, i, j + 1, w);// } else {//     addedge(i, j, i, 1, w);// }r[i][j]=getweight();}for(i = 1; i < n; i++)for(j = 1; j <= m; j++) {// w = getweight();c[i][j]=getweight();// addedge(i, j, i + 1, j, w);}
}
struct edge{int u,v,w;
};
inline int getid(int x,int y){return (x-1)*m+y;
}
struct MST{long long sum;vector<edge>vec;MST(){sum=0;}MST(int id){sum=0;for(signed i=1;i<n;++i)vec.push_back({getid(i,id),getid(i+1,id),c[i][id]});}void print(){cout<<"CHECK\n";cout<<"SUM = "<<sum<<'\n';for(auto x:vec)cout<<x.u<<' '<<x.v<<' '<<x.w<<'\n';}
}pre[M],suf[M];
int fa[N*M];
bool flg[N*M];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool cmp(edge x,edge y){return x.w<y.w;
}
MST merge(int id,bool opt){MST ans;ans.vec.clear();vector<edge>vec;for(signed i=1;i<=n;++i)fa[getid(i,id)]=getid(i,id),flg[getid(i,id)]=1;if(!opt){for(signed i=1;i<=n;++i){fa[getid(i,id-1)]=getid(i,id-1);flg[getid(i,id-1)]=0;fa[getid(i,1)]=getid(i,1);flg[getid(i,1)]=1;}}else{for(signed i=1;i<=n;++i){fa[getid(i,id+1)]=getid(i,id+1);flg[getid(i,id+1)]=0;fa[getid(i,m)]=getid(i,m);flg[getid(i,m)]=1;}}if(!opt)for(auto x:pre[id-1].vec)vec.push_back(x);else for(auto x:suf[id+1].vec)vec.push_back(x);for(signed i=1;i<n;++i)vec.push_back({getid(i,id),getid(i+1,id),c[i][id]});if(!opt)for(signed i=1;i<=n;++i)vec.push_back({getid(i,id-1),getid(i,id),r[i][id-1]});else for(signed i=1;i<=n;++i)vec.push_back({getid(i,id),getid(i,id+1),r[i][id]});sort(vec.begin(),vec.end(),cmp);if(!opt)ans.sum=pre[id-1].sum;else ans.sum=suf[id+1].sum;for(auto x:vec){int a=find(x.u),b=find(x.v),c=x.w;if(a==b)continue;if(!flg[a]||!flg[b])ans.sum+=c;if(!flg[a])fa[a]=b;else if(!flg[b])fa[b]=a;else fa[b]=a,ans.vec.push_back({a,b,c});}return ans;
}
long long solve(int l,int r){//do sth.for(signed i=1;i<=n;++i)fa[getid(i,1)]=getid(i,1),fa[getid(i,l-1)]=getid(i,l-1),fa[getid(i,r+1)]=getid(i,r+1),fa[getid(i,m)]=getid(i,m);vector<edge>vec;for(auto x:pre[l-1].vec)vec.push_back(x);for(auto x:suf[r+1].vec)vec.push_back(x);for(signed i=1;i<=n;++i)vec.push_back({getid(i,1),getid(i,m),::r[i][m]});// for(auto x:vec)cout<<x.u<<' '<<x.v<<' '<<x.w<<'\n';long long ans=pre[l-1].sum+suf[r+1].sum;// cout<<ans<<'\n';sort(vec.begin(),vec.end(),cmp);for(auto x:vec){int a=find(x.u),b=find(x.v),c=x.w;if(a==b)continue;fa[a]=b;ans+=c;// cout<<x.u<<' '<<x.v<<' '<<c<<'\n';}return ans;
}
signed main()
{// freopen("ds.in","r",stdin);// freopen("ds.out","w",stdout);// cin>>n>>m>>op>>lim>>seed;gen();pre[1]=MST(1);suf[m]=MST(m);for(signed i=2;i<=m;++i)pre[i]=merge(i,0);// for(signed i=1;i<=m;++i)pre[i].print();for(signed i=m-1;i>=1;--i)suf[i]=merge(i,1);// do sth.// q=read();read(q);while(q--){int l,r;read(l);read(r);// =read(),r=read();printf("%lld\n",solve(l,r));}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/866744.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[Java] 计算Java对象大小

序在Java应用程序的性能优化场景中,时常需要考虑Java对象的大小,以便评估后,进一步提出优化方案:占用内存的大小。(比如 本地内存) 对象数据在网络传输中占用的网络带宽 对象数据在存储时占用的磁盘空间 ...概述 对象大小如何计算对象大小包括俩部分的内容,对象头和对象…

并行前缀(Parallel Prefix)加法器

并行前缀(Parallel Prefix)加法器 并行前缀加法器的基本介绍 二进制加法器是目前数字计算单元中的重要模块,基础的加法器架构包括行波进位加法器(Ripple Carry Adder),超前进位加法器(Carry Look-Ahead Adder),进位选择加法器(Carry Select Adder)等。加法器的进位传…

科技风?写实风?教你设置多风格三维地图

概述 三维地图通过高度、深度、立体感等表现形式,能够真实还原地形地貌、城市建筑和空间结构。相比二维地图,它能够更清晰地展示复杂的地理数据,帮助用户快速理解空间关系,如地形起伏、建筑高度等。在实际应用中,我们可以将不同风格的三维地图作为项目的主体元素进行展示,…

【模拟电子技术】03-PN与二极管的特性

【模拟电子技术】03-PN与二极管的特性上节中有提到对PN结施加反向电压时,会使得PN结所形成的势垒增加,阻止多子到另一边。在掺杂浓度比较低的时候,外加电场加强,中间的耗尽层会加长,变成了一个粒子加速器,自由电子进去后不断加速。直到某一电场强度时,粒子加速足够大的时…

NocoBase 本周更新汇总:支持大规模数据量的导入和导出

本周更新包括:支持大规模数据量的导入和导出等。汇总一周产品更新日志,最新发布可以前往我们的博客查看。 NocoBase 目前更新包括的版本更新包括三个分支:main ,next和 develop。main :截止目前最稳定的版本,推荐安装此版本。 next:包含即将发布的新功能,经过初步测试的…

MSSQL:DBLINK连接oracle 19

无法为该请求检索数据。(Microsoft.SqlServer.Management.Sdk.Sfc)其他信息:执行Transact-SQL语句或批处理时发生了异常。(Microsoft.SqlServer.ConnectionInfo)在与SQL Server 建立连接时出现与网络相关的特定于实例的错误。未找到或无法访问服务器。请验证实例名称是否正…

五款强大报表软件助力企业提升数据分析效率

本文将为大家介绍五款功能强大的报表软件,包括山海鲸报表、JReport、Power BI、Zoho Analytics 和 SAP Crystal Reports。这些工具各具特色,能够帮助企业快速生成数据报表并进行深度分析。无论是数据可视化、报表定制、自动化生成还是与其他系统的集成,它们都能为企业的决策…

Linq中的设置操作 (C#):Distinct 和 DistinctBy、Except 和 ExceptBy、Intersect 和 IntersectBy、Union 和 UnionBy

LINQ 中的集运算是指根据相同或单独集合中是否存在等效元素来生成结果集的查询运算。 注:这些示例使用 System.Collections.Generic.IEnumerable<T> 数据源。 基于 System.Linq.IQueryProvider 的数据源使用 System.Linq.IQueryable<T> 数据源和表达式树。 表达式…

2025多校冲刺省选模拟赛3

过于困难,直接放弃2025多校冲刺省选模拟赛3\(T1\) A. 等差 \(100pts/100pts\)考虑哈希,每 \(k\) 个作为一组与上一组统一计算。取 \(Base>\) 值域时用高精度来存储并判断的正确性显然。观察到可行的最小的 \(k\) 单调不降,不妨直接枚举答案。暴力实现时间复杂度为 \(O(n…

还不会 Cert Manager 自动签发证书?一文掌握

相信很多小伙伴对于 Cert Manager 不陌生,Cert Manager 是 Kubernetes 上的证书管理工具,基于 ACME 协议与 Lets Encrypt 签发免费证书并为证书自动续期,实现永久免费使用证书。 本文将介绍如何使用 Cert Manager 实现自动签发证书并与 Rainbond 结合使用。 Cert Manager 概…

JAVA-Day 09:While循环语句

While循环 while循环格式 初始化语句; while(条件判断语句){ 循环体语句; 条件控制语句; } 初始化语句只执行一次 判断语句为True,循环继续 判断语句为False,循环结束 例: 世界最高山峰珠穆朗玛峰的高度为8844.43米=8844430毫米,假如有 一张足够大的纸,它的厚度为0.1毫米。…

rust学习十六.2、并发-利用消息传递进行线程间通讯

通过信道是rust的解决线程之间通信的2个工具之一,另外1个是是共享内存状态。 rust推出这个,明显地是因为受到go之类的影响。 在书籍中,作者提到go编程文档中的内容: 不要通过共享内存来通讯;而是通过通讯来共享内存(Do not communicate by sharing memory; instead, share…