当前位置: 首页 > 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.xdnf.cn/news/1312381.html

相关文章:

  • 设计索引的原则有哪些?
  • 八、SpringBoot项目热部署
  • 嵌入式硬件篇---电源电路
  • pwn定时器,ARM定时delay 外部中断用函数指针(统一)day55,56
  • 19.3 Transformers量化模型极速加载指南:4倍推理加速+75%显存节省实战
  • 头文件包含和前置声明
  • 什么是微前端?
  • 超越Transformer:大模型架构创新的深度探索
  • 数据结构:二叉平衡树
  • OpenCV 图像处理基础操作指南(二)
  • ClickHouse的学习与了解
  • 概率论基础教程第3章条件概率与独立性(三)
  • Linux sar命令详细使用指南
  • Qt 动态属性(Dynamic Property)详解
  • Qt 关于QString和std::string数据截断的问题- 遇到\0或者0x00如何处理?
  • 【经典上穿突破】副图/选股指标,双均线交叉原理,对价格波动反应灵敏,适合捕捉短期启动点
  • [1Prompt1Story] 注意力机制增强 IPCA | 去噪神经网络 UNet | U型架构分步去噪
  • PowerShell 第11章:过滤和比较(上)
  • 云安全 - The Big IAM Challenge
  • 二分查找。。
  • 智能合约:区块链时代的“数字契约革命”
  • AutoDL使用学习
  • 【Java web】Servlet 详解
  • CUDA 编程笔记:CUDA延迟隐藏
  • [优选算法专题二滑动窗口——最大连续1的个数 III]
  • huggingface TRL中是怎么获取参考模型的输出的
  • Swift 实战:实现一个简化版的 Twitter(LeetCode 355)
  • 新手向:GitCode疑难问题诊疗
  • Java 10 新特性及具体应用
  • 嵌入式硬件篇---电感串并联