啟發式合并 + 莫隊 戀戀的心跳大冒險

題目來源: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.pswp.cn/diannao/95744.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/95744.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/95744.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

JCTools 無鎖并發隊列基礎:ConcurrentCircularArrayQueue

ConcurrentCircularArrayQueue ConcurrentCircularArrayQueue 是一個抽象類&#xff0c;它為基于數組的并發循環隊列提供了基礎功能。從其命名可以看出幾個關鍵特性&#xff1a;??Concurrent??&#xff1a;常指無鎖并發。??Circular Array??&#xff1a;內部使用循環數…

力扣(LeetCode) ——622. 設計循環隊列(C語言)

題目&#xff1a;622. 設計循環隊列示例1&#xff1a; MyCircularQueue circularQueue new MyCircularQueue(3); // 設置長度為 3 circularQueue.enQueue(1); // 返回 true circularQueue.enQueue(2); // 返回 true circularQueue.enQueue(3); // 返回 true circularQueue.…

在JVM跑JavaScript腳本 | Oracle GraalJS 簡介與實踐

這是2024年初的 GraalVM 系列博文&#xff0c;當時寫了大綱&#xff0c;知道一年半后的現在才得以完成發布&#x1f604; 1、概述 實話說&#xff0c;標題的場景為小眾需求&#xff0c;日常開發基本用不到&#xff0c;我是最近在做一個低代碼輪子玩具 app-meta 需要實現 FaaS&…

基于 EC 數據與大模型技術實現天氣預報:從數據到上線的全棧方法

1. 先校準“EC 數據”與“AI 預報”的語境 EC 數據家族(常用) IFS/HRES:確定性全球模式,水平分辨率約 9 km,常用預報范圍 10 天; IFS/ENS:51 成員集合預報,提供 15 天概率信息; ERA5:再分析數據,小時級、0.25,可追溯至 1940 年,用作訓練/評測黃金基準。 AI 預報…

迭代器模式及優化

迭代器模式&#xff08;Iterator Pattern&#xff09;是一種行為型設計模式&#xff0c;用于提供一種統一的方式遍歷聚合對象&#xff08;如集合、容器&#xff09;中的元素&#xff0c;而無需暴露對象的內部實現細節。它將遍歷邏輯與聚合對象分離&#xff0c;使得遍歷操作可以…

純Qt手撕gb28181協議/gb28181協議服務端/gb28181協議設備端/gb28181設備模擬器/gb28181虛擬監控設備

一、前言說明 搞完onvif設備模擬器&#xff0c;總想著把28181設備模擬也實現&#xff0c;因為之前已經花了大力氣把28181平臺軟件端實現了&#xff0c;為了實現這個組件&#xff0c;頭發掉了一大把&#xff0c;專門把國標文檔看了好幾遍&#xff0c;逐行閱讀&#xff0c;針對需…

【滲透實戰】無下載器環境(curl/wget)下玩轉 Metasploit 自動利用

1. 背景與問題場景 在滲透測試或漏洞利用中&#xff0c;Metasploit&#xff08;MSF&#xff09;是業界最常用的框架之一。 其許多 RCE&#xff08;遠程代碼執行&#xff09;模塊在落地 payload&#xff08;如 Meterpreter 或反彈 shell&#xff09;時&#xff0c;采用了 CMD St…

jd-hotkey探測熱點key

對任意突發性的無法預先感知的熱點數據&#xff0c;包括并不限于熱點數據&#xff08;如突發大量請求同一個商品&#xff09;、熱用戶&#xff08;如惡意爬蟲刷子&#xff09;、熱接口&#xff08;突發海量請求同一個接口&#xff09;等&#xff0c;進行毫秒級精準探測到。然后…

C#WPF實戰出真汁07--【系統設置】--菜品類型設置

1、菜品設置介紹 菜品設置跟餐桌設置的功能目的是相同的&#xff0c;包括了新增&#xff0c;刪除&#xff0c;編輯&#xff0c;分頁&#xff0c;查詢&#xff0c;重置&#xff0c;全選&#xff0c;全消&#xff0c;列表功能&#xff0c;實現流程也是布局設計&#xff0c;后臺邏…

aave v3 存款與借款利息的計算方式

本文只涉及到利率計算的數學原理&#xff0c;不作源碼解析:存款首先我們假設小明在aave里面存了10000usdt&#xff0c;存的時候年化收益率是5%,那么半年后其存款的利息是多少呢?常規的計算方式如下:利息10000*5%*(存款的時長/一年的時長)這么做有什么問題呢&#xff1f;假設現…

Windows MCP.Net:基于.NET的Windows桌面自動化MCP服務器深度解析

&#x1f4cb; 目錄 項目概述 技術架構深度解析 核心功能模塊詳解 代碼實現分析 使用場景與實戰案例 性能優化與最佳實踐 擴展開發指南 總結與展望 項目概述 什么是Windows-MCP.Net&#xff1f; Windows MCP.Net是一個基于.NET 10.0開發的Windows桌面自動化MCP&…

Boost.Asio學習(7):Boost.Beast實現簡易http服務器

namespace beast boost::beast;beast::flat_buffer是一個用于 Boost.Asio 和 Boost.Beast 網絡讀寫的緩沖區實現。專為 一次性順序讀取 / 消費 場景設計&#xff0c;比 std::string 或 std::vector 高效&#xff0c;因為它是扁平內存結構&#xff08;contiguous memory&#x…

深入解析JVM內存區域劃分:從理論到實踐

Java虛擬機&#xff08;JVM&#xff09;是Java程序運行的核心環境&#xff0c;它負責管理內存分配、垃圾回收、字節碼執行等關鍵任務。理解JVM的內存區域劃分&#xff0c;對于優化Java應用性能、排查內存問題&#xff08;如OutOfMemoryError、StackOverflowError&#xff09;至…

滑窗|貪心|?滾動數組

lc17.08pair按身高升序、相同時體重降序排序結果是找體重序列的最長遞增子序列長度核心&#xff1a;轉化為二維最長遞增子序列問題求解vector<int> dp;for (auto& p : hw) {int w p.second;auto it lower_bound(dp.begin(), dp.end(), w);if (it dp.end()) {dp.pu…

深入理解數據庫架構:從原理到實踐的完整指南

一、數據庫存儲架構的多維度分類體系 1.1 基于數據組織方式的存儲架構分類 數據庫的存儲架構從根本上決定了其性能特征、適用場景和擴展能力。理解不同的數據組織方式是選擇合適數據庫技術的基礎&#xff0c;這種分類不僅反映了技術實現的差異&#xff0c;更體現了對不同業務需…

體彩排列三第2025218期號碼分析

大家好&#xff0c;本人蔡楚門來此平臺分享一下本期得經驗和思路&#xff0c;希望能夠給大家帶來好的運氣和靈感&#xff01;體彩排列三第2025218期號碼分析&#xff0c;大小號碼數字分析&#xff0c;上期開出全小號碼最多&#xff0c;最近兩期的開獎號碼全部都是全小號碼最多&…

java設計模式之迪米特法則介紹與說明

一、核心概念與目標 基本定義 迪米特法則的核心思想是&#xff1a;一個對象應該對其他對象盡可能少地了解&#xff0c;僅與直接關聯的對象&#xff08;即“朋友”&#xff09;通信&#xff0c;避免與“陌生人”產生直接交互。 直接朋友&#xff1a;包括當前對象的成員變量、方法…

2024-2025華為ICT大賽中國區 實踐賽昇騰AI賽道(高職組)全國總決賽 理論部分真題+解析

Part 1 昇騰AI全棧系統模塊(共6題)&#xff1a;1、許多計算芯片可以設計作為人工智能的計算芯片&#xff0c;但不同的芯片計算性能不同&#xff0c;昇騰計算芯片是一種()芯片。(單選題)A.CPU B.GPU C. NPU D.TPU正確答案&#xff1a;C解析&#xff1a;A項CPU中央處理器的架…

網絡安全和基礎設施安全局 (CISA) 表示微分段不再是可選的

網絡安全和基礎設施安全局 (CISA) 最近發布了一系列指導文件中的第一份&#xff0c;旨在幫助聯邦機構實施微分段&#xff0c;作為其零信任架構 (ZTA) 戰略的一部分&#xff0c;以遵守2022 年白宮的授權。 該文件《零信任中的微分段&#xff0c;第一部分&#xff1a;介紹和規劃…

Spring Boot SseEmitter 重復請求問題深度分析與解決方案

1. 前言 在使用 Spring Boot 開發流式接口(Server-Sent Events)時,我們遇到了一個令人困惑的問題:每次 SseEmitter 完成后,都會觸發第二次請求,導致重復請求檢測機制誤報。本文將詳細記錄問題的發現、分析過程以及最終的解決方案。 2. 系統架構背景 2.1 請求處理架構 …