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

启发式合并 + 莫队 恋恋的心跳大冒险

题目来源:2025 Wuhan University of Technology Programming Contest

比赛链接:Dashboard - 2025 Wuhan University of Technology Programming Contest - Codeforces

题目大意:

Solution:

首先肯定要预处理出以每个节点为起点出发获得的分数。然后就可以把树上的问题变成普通序列区间上的问题处理了。

很显然:

MAX 的答案就是区间长度

MIN 的答案就是区间众数的出现次数(若有多个众数,只算单个众数的出现次数)

于是答案就分为两个部分,一个树上预处理,一个维护区间众数出现次数

第一部分可以树上启发式合并用一个 set 维护当前子树内的连续区间,一个 multiset 维护当前所有连续区间的长度。当我们每加入一个新的点时,合并左右临接的区间,于是我们维护的区间一定是不相交的。

至于第二部分,直接离线询问莫队处理即可。

(第一次打的时候不知道如何用 set 维护区间,用数组存区间端点,又加了一个 goodr 表示当前维护的所有右端点,过程相对复杂,容易错,但好在没怎么调试,把两种写法代码都放在下面。)

Code1:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;#define N 100005int n,m,cnt,B,res;
int a[N],st[N],bel[N],dfn[N],siz[N],son[N],id[N],w[N],num[N],ld[N],rd[N],col[N],tot[N]; // num是数字i出现的次数struct Edge
{int next,to;
}ed[N << 1];struct Query
{int l,r,id;
}q[N],ans[N];multiset<int> s,goodr; // goodr存的是有效右端点int max(int x,int y) { return x > y ? x : y ; }int cmp(Query x,Query y)
{if(bel[x.l] == bel[y.l]) return x.r < y.r ;return bel[x.l] < bel[y.l] ;
}void added(int u,int v)
{ed[++ cnt].next = st[u];ed[cnt].to = v;st[u] = cnt;return;
}void pdfs(int x,int fa)
{siz[x] = 1;dfn[x] = ++ cnt;id[cnt] = x;for (int i = st[x]; ~i ;i = ed[i].next){int rec = ed[i].to;if(rec == fa) continue;pdfs(rec,x);siz[x] += siz[rec];if(!son[x] || siz[rec] > siz[son[x]]) son[x] = rec;}return;
}void calc(int x)
{x = a[x];if(!num[x]){if(ld[x - 1] && rd[x + 1]){int lenl,lenr;lenl = x - ld[x - 1];lenr = rd[x + 1] - x;auto it = s.lower_bound(lenl);s.erase(it);it = s.lower_bound(lenr);s.erase(it);s.insert(lenl + lenr + 1);int tl,tr;tl = ld[x - 1];tr = rd[x + 1];ld[rd[x + 1]] = tl,rd[ld[x - 1]] = tr;ld[x - 1] = rd[x + 1] = 0;it = goodr.lower_bound(x - 1);goodr.erase(x - 1);}else if(ld[x - 1]){int len = x - ld[x - 1];auto it = s.lower_bound(len);s.erase(it);s.insert(len + 1);ld[x] = ld[x - 1];ld[x - 1] = 0;rd[ld[x]] = x;it = goodr.lower_bound(x - 1);goodr.erase(x - 1);goodr.insert(x);}else if(rd[x + 1]){int len = rd[x + 1] - x;auto it = s.lower_bound(len);s.erase(it);s.insert(len + 1);rd[x] = rd[x + 1];rd[x + 1] = 0;ld[rd[x]] = x;}else{ld[x] = rd[x] = x;s.insert(1);goodr.insert(x);}}++ num[x];return;
}void del(int x)
{x = a[x];-- num[x];if(!num[x]){auto it = goodr.lower_bound(x);int tr = *it;int tl = ld[tr];int len = tr - tl + 1;it = s.lower_bound(len);s.erase(it);if(tl < x){int lenl = x - tl;s.insert(lenl);rd[tl] = x - 1;ld[x - 1] = tl;goodr.insert(x - 1);}else rd[tl] = 0;if(tr > x){int lenr = tr - x;s.insert(lenr);ld[tr] = x + 1;rd[x + 1] = tr;}else{ld[tr] = 0;it = goodr.lower_bound(x);goodr.erase(it);}}return;
}void dfs(int x,int fa,int op)
{for (int i = st[x]; ~i ;i = ed[i].next){int rec = ed[i].to;if(rec == fa || rec == son[x]) continue;dfs(rec,x,0);}if(son[x]) dfs(son[x],x,1);calc(x);for (int i = st[x]; ~i ;i = ed[i].next){int rec = ed[i].to;if(rec == fa || rec == son[x]) continue;for (int j = dfn[rec];j <= dfn[rec] + siz[rec] - 1;++ j)calc(id[j]);}auto it = s.rbegin();w[x] = *it;if(!op){for (int i = dfn[x];i <= dfn[x] + siz[x] - 1;++ i)del(id[i]);}return;
}void add(int x)
{x = w[x];-- tot[col[x]];++ col[x];++ tot[col[x]];res = max(res,col[x]);return;
}void sub(int x)
{x = w[x];-- tot[col[x]];if(!tot[col[x]] && res == col[x]) -- res;-- col[x];++ tot[col[x]];return;
}int main()
{memset(st,-1,sizeof st);scanf("%d%d",&n,&m),cnt = res = 0,B = (int)sqrt(n);for (int i = 1;i <= n;++ i) scanf("%d",&a[i]),bel[i] = (i - 1) / B + 1;for (int i = 1,u,v;i < n;++ i)scanf("%d%d",&u,&v),added(u,v),added(v,u);cnt = 0;pdfs(1,0);dfs(1,0,1);for (int i = 1;i <= m;++ i)scanf("%d%d",&q[i].l,&q[i].r),q[i].id = i;sort(q + 1,q + m + 1,cmp);int l,r;l = 1,r = 0;for (int i = 1;i <= m;++ i){while (l > q[i].l) add(-- l);while (l < q[i].l) sub(l ++);while (r < q[i].r) add(++ r);while (r > q[i].r) sub(r --);ans[q[i].id].l = res;ans[q[i].id].r = r - l + 1;}for (int i = 1;i <= m;++ i) printf("%d %d\n",ans[i].l,ans[i].r);return 0;
}

Code2:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;#define N 100005int n,m,cnt,B,res;
int a[N],st[N],bel[N],dfn[N],siz[N],son[N],id[N],w[N],num[N],ld[N],rd[N],col[N],tot[N];struct Edge
{int next,to;
}ed[N << 1];struct Query
{int l,r,id;
}q[N],ans[N];multiset<int> len;
set<pair <int,int> > s;int max(int x,int y) { return x > y ? x : y ; }int cmp(Query x,Query y)
{if(bel[x.l] == bel[y.l]) return x.r < y.r ;return bel[x.l] < bel[y.l] ;
}void added(int u,int v)
{ed[++ cnt].next = st[u];ed[cnt].to = v;st[u] = cnt;return;
}void pdfs(int x,int fa)
{siz[x] = 1;dfn[x] = ++ cnt;id[cnt] = x;for (int i = st[x]; ~i ;i = ed[i].next){int rec = ed[i].to;if(rec == fa) continue;pdfs(rec,x);siz[x] += siz[rec];if(!son[x] || siz[rec] > siz[son[x]]) son[x] = rec;}return;
}void calc(int x)
{x = a[x];int lenl,lenr;if(!num[x]){auto it = s.upper_bound({x,N});int flag = 0;if(it != s.end() && it != s.begin()){auto rseg = *it;-- it;auto lseg = *it;++ it;lenl = lseg.second - lseg.first + 1;lenr = rseg.second - rseg.first + 1;if(lseg.second == x - 1 && rseg.first == x + 1){auto itlen = len.lower_bound(lenl);len.erase(itlen);itlen = len.lower_bound(lenr);len.erase(itlen);len.insert(lenl + lenr + 1);s.erase({lseg.first,lseg.second});s.erase({rseg.first,rseg.second});s.insert({lseg.first,rseg.second});flag = 1;}}if(!flag){if(it != s.end()){auto rseg = *it;lenr = rseg.second - rseg.first + 1;if(rseg.first == x + 1){auto itlen = len.lower_bound(lenr);len.erase(itlen);len.insert(lenr + 1);s.erase({rseg.first,rseg.second});s.insert({x,rseg.second});flag = 1;}}if(!flag){if(it != s.begin()){-- it;auto lseg = *it;++ it;lenl = lseg.second - lseg.first + 1;if(lseg.second == x - 1){auto itlen = len.lower_bound(lenl);len.erase(itlen);len.insert(lenl + 1);s.erase({lseg.first,lseg.second});s.insert({lseg.first,x});flag = 1;}}}if(!flag){s.insert({x,x});len.insert(1);}}}++ num[x];return;
}void del(int x)
{x = a[x];-- num[x];if(!num[x]){auto it = s.upper_bound({x,N});-- it;auto seg = *it;int lenl = x - seg.first;int lenr = seg.second - x;s.erase({seg.first,seg.second});if(seg.first < x && seg.second > x){auto itlen = len.lower_bound(lenl + lenr + 1);len.erase(itlen);len.insert(lenl);len.insert(lenr);s.insert({seg.first,x - 1});s.insert({x + 1,seg.second});}else if(seg.first < x){auto itlen = len.lower_bound(lenl + 1);len.erase(itlen);len.insert(lenl);s.insert({seg.first,x - 1});}else if(seg.second > x){auto itlen = len.lower_bound(lenr + 1);len.erase(itlen);len.insert(lenr);s.insert({x + 1,seg.second});}else{auto itlen = len.lower_bound(1);len.erase(itlen);}}return;
}void dfs(int x,int fa,int op)
{for (int i = st[x]; ~i ;i = ed[i].next){int rec = ed[i].to;if(rec == fa || rec == son[x]) continue;dfs(rec,x,0);}if(son[x]) dfs(son[x],x,1);calc(x);for (int i = st[x]; ~i ;i = ed[i].next){int rec = ed[i].to;if(rec == fa || rec == son[x]) continue;for (int j = dfn[rec];j <= dfn[rec] + siz[rec] - 1;++ j)calc(id[j]);}auto it = len.rbegin();w[x] = *it;if(!op){for (int i = dfn[x];i <= dfn[x] + siz[x] - 1;++ i)del(id[i]);}return;
}void add(int x)
{x = w[x];-- tot[col[x]];++ col[x];++ tot[col[x]];res = max(res,col[x]);return;
}void sub(int x)
{x = w[x];-- tot[col[x]];if(!tot[col[x]] && res == col[x]) -- res;-- col[x];++ tot[col[x]];return;
}int main()
{memset(st,-1,sizeof st);scanf("%d%d",&n,&m),cnt = res = 0,B = (int)sqrt(n);for (int i = 1;i <= n;++ i) scanf("%d",&a[i]),bel[i] = (i - 1) / B + 1;for (int i = 1,u,v;i < n;++ i)scanf("%d%d",&u,&v),added(u,v),added(v,u);cnt = 0;pdfs(1,0);dfs(1,0,1);for (int i = 1;i <= m;++ i)scanf("%d%d",&q[i].l,&q[i].r),q[i].id = i;sort(q + 1,q + m + 1,cmp);int l,r;l = 1,r = 0;for (int i = 1;i <= m;++ i){while (l > q[i].l) add(-- l);while (l < q[i].l) sub(l ++);while (r < q[i].r) add(++ r);while (r > q[i].r) sub(r --);ans[q[i].id].l = res;ans[q[i].id].r = r - l + 1;}for (int i = 1;i <= m;++ i) printf("%d %d\n",ans[i].l,ans[i].r);return 0;
}

http://www.lryc.cn/news/623077.html

相关文章:

  • 【机器学习深度学习】OpenCompass:支持的开源评估数据集及使用差异
  • 告别重复纹理:用Substance Designer构建UE5程序化地貌材质系统
  • SysTick寄存器(嘀嗒定时器实现延时)
  • EP1C12F324I7N Altera Cyclone FPGA
  • [创业之路-550]:公司半年度经营分析会 - 解决方案汇总
  • Vue2.x核心技术与实战(一)
  • Java 学习笔记(基础篇3)
  • 嵌入式硬件篇---电源电路
  • php版的FormCreate使用注意事项
  • 从频繁告警到平稳发布:服务冷启动 CPU 风暴优化实践00
  • Flow-GRPO:通过在线 RL 训练 Flow matching 模型
  • 【OpenGL】LearnOpenGL学习笔记10 - 平行光、点光源、聚光灯
  • 2020/12 JLPT听力原文 问题二 2番
  • CSDN部分内容改为视频转到B站-清单
  • Flink Stream API 源码走读 - print()
  • B3865 [GESP202309 二级] 小杨的 X 字矩阵(举一反三)
  • 矩阵链相乘的最少乘法次数(动态规划解法)
  • 深入了解 swap:作用、局限与分区建立
  • Hadoop面试题及详细答案 110题 (16-35)-- HDFS核心原理与操作
  • 鸿蒙应用开发和Vue网页开发中生命周期的区别
  • (论文速读)ViDAR:视觉自动驾驶预训练框架
  • leetcode hot100数组:缺失的第一个正数
  • Winsows系统去除右键文件显示的快捷列表
  • Win11家庭版docker安装Minio
  • windows环境下使用vscode以及相关插件搭建c/c++的编译,调试环境
  • 93、23种设计模式之抽象工厂模式
  • MySQL建表练习
  • GaussDB 数据库架构师修炼(十三)安全管理(3)-数据库审计
  • 人工智能中的(特征选择)数据过滤方法和包裹方法
  • Linux 下 安装 matlab 2025A