題解 洛谷 P3793 由乃救爺爺
阿新 • • 發佈:2022-12-12
1. 題面描述
給定長為 \(n\) 的序列,\(m\) 次詢問,查詢區間最大值。
\(n,m\le 10^7\),資料隨機。
2. 分析
經典的靜態區間最小值問題,經典題目配經典演算法,考慮到 ST 表和笛卡爾樹。
而時間複雜度為 \(O(nlogn)\) 的 ST 表無法通過本題,於是考慮笛卡爾樹。
首先構建一顆笛卡爾樹。
根據笛卡爾樹性質可知,對於區間 \([l,r]\),最大值即為笛卡爾樹上 \(lca(l,r)\) 的值。
說明:
根據二叉搜尋樹性質,可知 \(l\le lca(l,r)\le r\),滿足最大值在 \([l,r]\) 範圍內。
根據大根堆性質,可知 \(lca(l,r)\)
為區間 \([l,r]\) 的最大值。
於是問題就轉變為 \(n\) 個節點的樹,\(m\) 次詢問,查詢 LCA。
這裡可以選擇 Tarjan 演算法離線以 \(O(m)\) 的時間複雜度求解 LCA。
不過因為本體資料隨機,笛卡爾樹期望樹高為 \(logn\) 數量級。同時詢問隨機,每次詢問所查詢的 LCA 不會過深,於是可以考慮從根開始暴力尋找 LCA。經測試,可以通過本題。
3. 程式碼
#include <bits/stdc++.h> using namespace std; const int N=20000005; namespace GenHelper { unsigned z1,z2,z3,z4,b; unsigned rand_() { b=((z1<<6)^z1)>>13; z1=((z1&4294967294U)<<18)^b; b=((z2<<2)^z2)>>27; z2=((z2&4294967288U)<<2)^b; b=((z3<<13)^z3)>>21; z3=((z3&4294967280U)<<7)^b; b=((z4<<3)^z4)>>12; z4=((z4&4294967168U)<<13)^b; return (z1^z2^z3^z4); } } void srand(unsigned x) {using namespace GenHelper; z1=x; z2=(~x)^0x233333333U; z3=x^0x1234598766U; z4=(~x)+51;} int read() { using namespace GenHelper; int a=rand_()&32767; int b=rand_()&32767; return a*32768+b; } int n,m,s,top; int a[N],son[N][2],sta[N]; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>n>>m>>s; srand(s); for (int i=1; i<=n; i++) { a[i]=read(); while (top && a[sta[top]]<a[i]) son[i][0]=sta[top--]; if (top) son[sta[top]][1]=i; sta[++top]=i; } int rt=sta[1]; unsigned long long ans=0; while (m--) { int l=read()%n+1,r=read()%n+1; if (l>r) swap(l,r); int p=rt; while (true) { if (l<=p && p<=r) {ans+=a[p]; break;} p=son[p][p<l]; } } cout<<ans<<'\n'; return 0; }
本文完。