Luogu4755 Beautiful Pair 最值分治、主席树

传送门


整天做一些模板题感觉药丸

\(val_i\)表示第\(i\)个位置的值

看到区间最大值考虑最值分治。对于当前的区间\([l,r]\),找到区间最大值\(mid\),递归\([l,mid-1]\)\([mid+1,r]\),然后考虑pair\((i,j)(i \in [l,mid] , r \in [mid,r])\)的贡献。

\([l,mid]\)\([mid,r]\)中较短的一段区间,那么对于扫到的一个位置\(i\),它的贡献就是另一段区间中值小于等于\(\lfloor \frac{val_{mid}}{val_i} \rfloor\)的位置的数量,使用主席树维护即可。

#include<bits/stdc++.h>
//this code is written by Itst
using namespace std;

int read(){
    int a = 0; char c = getchar();
    while(!isdigit(c)) c = getchar();
    while(isdigit(c)){
        a = a * 10 + c - 48;
        c = getchar();
    }
    return a;
}

#define ll long long
#define lb lower_bound
#define ub upper_bound
const int _ = 1e5 + 7;
namespace segTree{
    int lch[_ * 20] , rch[_ * 20] , sum[_ * 20] , cntN;

#define mid ((l + r) >> 1)
    
    int modify(int x , int l , int r , int tar){
        int t = ++cntN;
        sum[t] = sum[x] + 1; lch[t] = lch[x]; rch[t] = rch[x];
        if(l == r) return t;
        if(mid >= tar) lch[t] = modify(lch[t] , l , mid , tar);
        else rch[t] = modify(rch[t] , mid + 1 , r , tar);
        return t;
    }

    int query(int x , int l , int r , int R){
        if(r <= R) return sum[x];
        int sum = query(lch[x] , l , mid , R);
        if(mid < R) sum += query(rch[x] , mid + 1 , r , R);
        return sum;
    }
}
int rt[_] , val[_] , lsh[_] , ST[21][_] , logg2[_] , N , cntL;

int cmp(int a , int b){return val[a] > val[b] ? a : b;}

void init(){
    logg2[0] = -1;
    for(int i = 1 ; i <= N ; ++i){
        ST[0][i] = i;
        logg2[i] = logg2[i >> 1] + 1;
    }
    for(int i = 1 ; 1 << i <= N ; ++i)
        for(int j = 1 ; j + (1 << i) - 1 <= N ; ++j)
            ST[i][j] = cmp(ST[i - 1][j] , ST[i - 1][j + (1 << (i - 1))]);
}

int qST(int l , int r){
    int t = logg2[r - l + 1];
    return cmp(ST[t][l] , ST[t][r - (1 << t) + 1]);
}

ll solve(int l , int r){
    if(l > r) return 0;
    if(l == r) return lsh[val[l]] == 1 ? 1 : 0;
    int Mid = qST(l , r) , w = lsh[val[Mid]];
    ll sum = solve(l , Mid - 1) + solve(Mid + 1 , r);
    int L = l , R = Mid , rgeL = Mid , rgeR = r;
    if(Mid - l > r - Mid){
        swap(rgeL , L); swap(rgeR , R);
    }
    while(L <= R){
        int num = ub(lsh + 1 , lsh + cntL , w / lsh[val[L]]) - lsh - 1;
        if(num)
            sum += segTree::query(rt[rgeR] , 1 , cntL , num) - segTree::query(rt[rgeL - 1] , 1 , cntL , num);
        ++L;
    }
    return sum;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("in","r",stdin);
    //freopen("out","w",stdout);
#endif
    N = read();
    for(int i = 1 ; i <= N ; ++i)
        val[i] = lsh[i] = read();
    sort(lsh + 1 , lsh + N + 1);
    cntL = unique(lsh + 1 , lsh + N + 1) - lsh;
    for(int i = 1 ; i <= N ; ++i){
        val[i] = lb(lsh + 1 , lsh + cntL , val[i]) - lsh;
        rt[i] = segTree::modify(rt[i - 1] , 1 , cntL , val[i]);
    }
    init();
    cout << solve(1 , N);
    return 0;
}
posted @ 2019-04-29 19:20  cjoier_Itst  阅读(322)  评论(1编辑  收藏  举报