当前位置: 首页 > 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.dtcms.com/a/334378.html

相关文章:

  • 汽车大灯ABD算法介绍
  • 【算法】——力扣hot100常用算法技巧
  • leetcode_ 739 每日温度
  • 分享一个大数据的源码实现 基于Hadoop的二手车市场数据分析与可视化 基于Spark的懂车帝二手车交易数据可视化分析系统
  • Windows MCP.Net:革命性的 .NET Windows 桌面自动化 MCP 服务器
  • 嵌入式硬件篇---电容电感
  • 【C++】动态内存管理
  • 嵌入式硬件篇---电平转换电路
  • Python-深度学习(一)
  • Flutter开发 网络请求
  • Obot MCP 网关:用于安全管理 MCP 服务器采用的开源平台
  • DINOv3 论文精读(逐段解析)
  • 一文速通Python并行计算:14 Python异步编程-协程的管理和调度
  • CPP运算符优先级
  • 2508C++,支持rdma通信的高性能rpc库
  • 软件SPI实现(3):SPI协议测试(使用W25Q64)
  • Jenkins常见问题及解决方法
  • 计算机存储器分类和层次结构详解
  • 027 动静态库 —— 静态库
  • Docker数据卷挂载和本地目录挂载
  • 八、SpringBoot项目热部署
  • Java服务自动停止原因及查找方法
  • Cloudflare Tunnels 部署与隧道异常关闭的解决方案
  • 攻击者如何毒害人工智能工具和防御系统
  • 【更新公告】C++算法·线段树
  • CF每日3题(1500-1700)
  • 《WINDOWS 环境下32位汇编语言程序设计》第2章 准备编程环境
  • IO流-序列化流
  • 记录 GMS 认证相关条件
  • 玄机靶场 | 日志分析-Tomcat日志分析