单调队列维护区间最值

https://blog.csdn.net/qq_41021816/article/details/81428225?utm_medium=distribute.pc_feed_404.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_feed_404.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecas

假设求一个序列中所有长度为k的区间的最值,我们在求1到k区间的最值后,2到k+1区间的最值可以用2到k区间的最值与第k+1个值进行比较,可以通过单调队列维护2到k区间的最值

2020牛客多校第二场,单调队列维护二维区间最值

#include<bits/stdc++.h>
#define ri register int
#define ll long long
#define EPS 1e-7
#define INF 0x7fffffff
#define lb(x) x&(-x)
#define fast ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
const inline int read(){
    int k = 0, f = 1; char c = getchar();
    for(;!isdigit(c); c = getchar())
        if(c == '-') f = -1;
    for(;isdigit(c); c = getchar())
        k = k * 10 + c - '0';
    return k * f;
}
int n, m, k;
const int maxn = 5005;
int a[maxn][maxn], h[maxn][maxn];
int que[maxn];
ll ans = 0;
int gcd(int x,int y){return x%y==0?y:gcd(y,x%y);}
void solve(){
    for(ri i = 1; i <= n; ++i)
        for(ri j = 1; j <= m; ++j)
            a[i][j] = i * j / gcd(i, j);
        for(ri i = 1; i <= n; ++i){
            int head = 1, tail = 1;
            que[tail] = 0;
            for(ri j = 1; j < k; ++j){
                while(tail >= head && a[i][j] > a[i][que[tail]])
                    tail--;
                que[++tail] = j;
            }
            for(ri j = k; j <= m; ++j){
                while(tail >= head && j - que[head] >= k)
                    head++;
                while(tail >= head && a[i][j] > a[i][que[tail]])
                    tail--;
                que[++tail] = j;
                h[i][j] = a[i][que[head]];
            }
        }
        for(ri j = k; j <= m; ++j){
            int head = 1, tail = 1;
            que[tail] = 0;
            for(ri i = 1; i < k; ++i){
                while(tail >= head && h[i][j] > h[que[tail]][j])
                    tail--;
                que[++tail] = i;
            }
            for(ri i = k; i <= n; ++i){
                while(tail >= head && i - que[head] >= k)
                    head++;
                while(tail >= head && h[i][j] > h[que[tail]][j])
                    tail--;
                que[++tail] = i;
                ans += h[que[head]][j];
            }
        }
}
int main(){
    fast;
    cin >> n >> m >> k;
    solve();
    cout << ans << "\n";
    return 0;
}
View Code

 

posted @ 2020-08-05 16:36  kojoker  阅读(321)  评论(0)    收藏  举报