• 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} floor)的位置的数量,使用主席树维护即可。

    #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;
    }
    
  • 相关阅读:
    软件开发流程概要(笔记)
    (转)HTTP协议及其POST与GET操作差异 & C#中如何使用POST、GET等
    (转)敏捷开发简介
    (转)从零开始学习ASP.NET MVC 1.0 (一) 开天辟地入门篇
    WinForm二三事(二)异步操作
    TSQL变量操作详解
    C#委托和多线程文章收藏
    psad, fwknop, 和fwsnort等著名开源安全软件的开发者谈Linux防火墙
    最通俗易懂的面向对象著作
    找到一本适合自己的SQL Server 2008入门书
  • 原文地址:https://www.cnblogs.com/Itst/p/10792371.html
Copyright © 2020-2023  润新知