2 solutions
-
0
提供五种写法供参考。
优先队列写法(洛谷要开O2优化才能过)
#include <iostream> #include <queue> #define int long long #define endl '\n' #define QAQ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; const int N=1e6+5; int a[N]; struct p{ int x,id; bool operator <(const p&r) const//从小到大 { if(x!=r.x) return x<r.x; else return id<r.id; } bool operator >(const p&r) const//从大到小 { if(x!=r.x) return x>r.x; else return id>r.id; } }; priority_queue <p> q;//从大到小的优先队列(后面的小于前面的(大根堆 priority_queue <p,vector<p>,greater<p>> q1;//从小到大的优先队列(后面的都要大于前面的(小根堆 void solve() { int n,k; cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { q1.push((p){a[i],i}); while(i-q1.top().id>=k)//如果已经超出窗口范围就删掉 q1.pop(); if(i>=k)//当i≥k,每移动一格就输出队头(最小值) cout<<q1.top().x<<' '; } cout<<endl; for(int i=1;i<=n;i++)//同理 { q.push((p){a[i],i}); while(i-q.top().id>=k)//如果已经超出窗口范围就删掉 q.pop(); if(i>=k)//当i≥k,每移动一格就输出队头(最大值) cout<<q.top().x<<' '; } } signed main() { QAQ; int t=1; // cin>>t; while(t--) solve(); return 0; }
单调队列写法
#include <iostream> #include <cmath> #include <deque> #define int long long #define endl '\n' #define QAQ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; const int N=1e6+5; struct Num{ int num,id; }a[N]; deque <Num> deq; void solve() { int n,k; cin>>n>>k; for(int i=1;i<=n;i++) { cin>>a[i].num; a[i].id=i; } for(int i=1;i<=n;i++) { while((!deq.empty())&&a[i].num<=deq.back().num)//保持单调递增 deq.pop_back(); if((!deq.empty())&&i-deq.front().id+1>k)//超出窗口就删掉 deq.pop_front(); deq.push_back(a[i]); if(i>=k) cout<<deq.front().num<<' '; } cout<<endl; deq.clear(); for(int i=1;i<=n;i++) { while((!deq.empty())&&a[i].num>=deq.back().num)//保持单调递减 deq.pop_back(); if((!deq.empty())&&i-deq.front().id+1>k) deq.pop_front(); deq.push_back(a[i]); if(i>=k) cout<<deq.front().num<<' '; } } signed main() { QAQ; int t=1; // cin>>t; while(t--) solve(); }
并查集写法(一位佬提供的
#include<bits/stdc++.h> using namespace std; const int N = 1e6 + 10; typedef pair<int,int> PII; PII s[N]; int ans[N]; struct DSU{ vector<int> f; DSU(int n):f(n){ iota(f.begin(),f.end(),0); } int find(int x){ return f[x] == x ? x : f[x] = find(f[x]); } void merge(int a,int b){ int fa=find(a),fb = find(b); if(fa == fb)return ; f[fb] = fa; } }; int main(){ int n, k ; ios::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); cin >> n >> k; for(int i=1;i<=n;i++){ cin >> s[i].first; s[i].second = i; } sort(s + 1,s + n + 1); {// 最小 DSU ds(n + 2); for(int i = 1; i <= n ;i ++){ int x = s[i].second,w = s[i].first; int l = max(x - k + 1,1),r = x; for(int j = ds.find(l);j <= r; j = ds.find(j)){ ans[j] = w; ds.merge(j + 1,j); } } for(int i=1;i <= n - k + 1;i++){ cout << ans[i] <<" \n"[i == n - k + 1]; } } {// 最大 DSU ds(n + 2); for(int i = n; i;i --){ int x = s[i].second,w = s[i].first; int l = max(x - k + 1,1),r = x; for(int j = ds.find(l);j <= r; j = ds.find(j)){ ans[j] = w; ds.merge(j + 1,j); } } for(int i=1;i <= n - k + 1;i++){ cout << ans[i] <<" \n"[i == n - k + 1]; } } }
线段树写法
#include <iostream> #include <cmath> #define int long long #define endl '\n' #define QAQ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; const int N=1e6+5; struct Tree{ int l,r,minn,maxx; }tree[4*N]; int n,k,x,y; int a[N]; void pre()//预处理最值 { for(int i=1;i<=4*N;i++) { tree[i].minn=1e18; tree[i].maxx=-1e18; } } void build(int root,int l,int r)//建立二叉树 储存每个窗口最大最小值 { tree[root].l=l; tree[root].r=r; if(l>r) return ; if(l==r) { tree[root].minn=a[l]; tree[root].maxx=a[l]; return ; } int mid=l+r>>1; build(root*2,l,mid); build(root*2+1,mid+1,r); tree[root].minn=min(tree[root*2].minn,tree[root*2+1].minn); tree[root].maxx=max(tree[root*2].maxx,tree[root*2+1].maxx); } int query1(int root,int l,int r)//查询最小值 { if(l>r) return 0; if(x<=l&&y>=r) return tree[root].minn; int mid=(l+r)>>1; int sum=1e18; if(x<=mid) sum=min(sum,query1(root*2,l,mid)); if(y>mid) sum=min(sum,query1(root*2+1,mid+1,r)); return sum; } int query2(int root,int l,int r)//查询最大值 { if(l>r) return 0; if(x<=l&&y>=r) return tree[root].maxx; int mid=(l+r)>>1; int sum=-1e18; if(x<=mid) sum=max(sum,query2(root*2,l,mid)); if(y>mid) sum=max(sum,query2(root*2+1,mid+1,r)); return sum; } void solve() { cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; pre(); build(1,1,n); for(int i=k;i<=n;i++)//最小 { x=i-k+1; y=i; cout<<query1(1,1,n)<<' '; } cout<<endl; for(int i=k;i<=n;i++)//最大 { x=i-k+1; y=i; cout<<query2(1,1,n)<<' '; } } signed main() { QAQ; int t=1; // cin>>t; while(t--) solve(); return 0; }
ST表(Sparse Table,稀疏表)---解决RMQ问题
#include <iostream> #include <cmath> #define int long long #define endl '\n' #define QAQ ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) using namespace std; const int N=1e6+5; int f[25][N]; int n,k; void pre1()//预处理存最小 { for(int i=1;i<=log2(n);i++) { for(int j=1;j<=n-(1<<i)+1;j++) { f[i][j]=min(f[i-1][j],f[i-1][j+(1<<(i-1))]); } } } int query1(int l,int r)//查询区间最小值 { int s=log2(r-l+1); return min(f[s][l],f[s][r-(1<<s)+1]); } void pre2()//预处理存最大 { for(int i=1;i<=log2(n);i++) { for(int j=1;j<=n-(1<<i)+1;j++) { f[i][j]=max(f[i-1][j],f[i-1][j+(1<<(i-1))]); } } } int query2(int l,int r)//查询区间最大值 { int s=log2(r-l+1); return max(f[s][l],f[s][r-(1<<s)+1]); } void solve() { cin>>n>>k; for(int i=1;i<=n;i++) cin>>f[0][i]; pre1(); for(int i=1;i<=n-k+1;i++) cout<<query1(i,i+k-1)<<' '; cout<<endl; pre2(); for(int i=1;i<=n-k+1;i++) cout<<query2(i,i+k-1)<<' '; } signed main() { QAQ; int t=1; // cin>>t; while(t--) solve(); return 0; }
线段树写法在oj上MLE了但是在落谷过了的。
Information
- ID
- 1108
- Time
- 1000ms
- Memory
- 16MiB
- Difficulty
- 6
- Tags
- # Submissions
- 20
- Accepted
- 10
- Uploaded By