Codeforces Round #361 (Div. 2) D - Friends and Subsequences

题目大意:给你两个长度为n的数组a, b,问你有多少个问你有多少个区间满足

a中最大值等于b中最小值。

思路:我本来的想法是用单调栈求出每个点的管辖区间,然后问题就变成了巨麻烦的线段覆盖问题,就爆炸写了

一晚上假算法。正解就是枚举一个端点,然后二分找右端点的区间,因为满足一个很神奇的单调性,然后st表维护

一下区间最值就好了。

#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>

using namespace std;

const int N = 2e5 + 7;
const int M = 1e5 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 420047;

int n, a[N], b[N], bin[20], Log[N], mx[20][N], mn[20][N];

void calRmq() {
    bin[0] = 1; Log[0] = -1;
    for(int i = 1; i < 20; i++) bin[i] = bin[i - 1] * 2;
    for(int i = 1; i < N; i++)  Log[i] = Log[i / 2] + 1;

    for(int i = 1; i <= n; i++) mx[0][i] = a[i];
    for(int i = 1; i <= n; i++) mn[0][i] = b[i];

    for(int i = 1; i <= Log[n]; i++) {
        for(int j = 1; j <= n; j++) {
            if(j + bin[i] - 1 <= n) {
                mn[i][j] = min(mn[i - 1][j], mn[i - 1][j + bin[i - 1]]);
                mx[i][j] = max(mx[i - 1][j], mx[i - 1][j + bin[i - 1]]);
            }
        }
    }
}

int getVal(int x, int y, int op) {
    int t = Log[y - x + 1];
    if(op) return max(mx[t][x], mx[t][y - bin[t] + 1]);
    return min(mn[t][x], mn[t][y - bin[t] + 1]);
}

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for(int i = 1; i <= n; i++) {
        scanf("%d", &b[i]);
    }

    calRmq();

    LL ans = 0;
    for(int i = 1; i <= n; i++) {
        int l = i, r = n, mid, ret1 = -1, ret2 = -1;
        while(l <= r) {
            mid = l + r >> 1;
            int valMin = getVal(i, mid, 0);
            int valMx = getVal(i, mid, 1);
            if(valMin > valMx) l = mid + 1;
            else if(valMin < valMx) r = mid - 1;
            else ret1 = mid, r = mid - 1;
        }


        l = i, r = n;
        while(l <= r) {
            mid = l + r >> 1;
            int valMin = getVal(i, mid, 0);
            int valMx = getVal(i, mid, 1);
            if(valMin > valMx) l = mid + 1;
            else if(valMin < valMx) r = mid - 1;
            else ret2 = mid, l = mid + 1;
        }

        if(ret1 != -1) {
            ans += ret2 - ret1 + 1;
        }
    }

    printf("%lld\n", ans);
    return 0;
}

/*
*/
#include<bits/stdc++.h>
#define LL long long
#define fi first
#define se second
#define mk make_pair
#define pii pair<int, int>

using namespace std;

const int N = 1e5;
const int M = 1e6 + 7;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1e9 +7;

int mm[N];
struct ST
{
    int dp[N][20],ty;
    void build(int n,int b[],int _ty)
    {
        ty=_ty;
        for(int i=1;i<=n;i++)
            dp[i][0]=ty*b[i];
        for(int j=1;j<=mm[n];j++)
            for(int i=1;i+(1<<j)-1<=n;i++)
                dp[i][j]=max(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
    }
    int query(int x,int y)
    {
        int k=mm[y-x+1];
        return ty*max(dp[x][k],dp[y-(1<<k)+1][k]);
    }
}rmq;

int a[N];
int main() {

    for(int i=-(mm[0]=-1);i<N;i++)
        mm[i]=mm[i-1]+((i&(i-1))==0);

    int n; scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    rmq.build(n, a, 1);

    while(1) {
        int x, y; scanf("%d%d", &x, &y);
        cout << rmq.query(x, y) << endl;
    }
    return 0;
}

还有一个很神奇的st表

猜你喜欢

转载自www.cnblogs.com/CJLHY/p/9233358.html