• 主席树的妙用——Just h-index


    题目传送门:https://ac.nowcoder.com/acm/contest/1107/C

    题意:给出一个区间,求最大的 h ,使得区间内至少有 h 个数 大于等于 h.

    思路:1.需要区间有序,那么就需要使用 主席树。

       2.二分答案。

        2.1 —— 一开始我的思路是直接对每一个查询二分答案 h。

            然后判断第 len(区间个数)-h+1 小是否大于等于 h,这样二分得出最大h,但是T了。

            一开始以为是卡常了,于是各种 骚操作 还是没有什么卵用。

            于是在一次优化 “ 由于n小可以去掉离散化” ,依然T了之后。忽然发现可以直接二分位置,也就是直接在主席树查询中直接找到答案。

        2.2 —— 在查询过程中,我们就不断的二分位置,判定条件是:

            主席树中,

            h右边的个数是否大于h,如果是,那么就往右子树走,否则就往左子树走。

            记得不要离散化,因为我们二分的是位置,而不是大小。

     

    //#pragma comment(linker, "/STACK:1024000000,1024000000")
    //#pragma GCC optimize(2)
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef double dou;
    typedef long long ll;
    typedef pair<int, int> pii;
    typedef map<int, int> mii;
    
    #define pai acos(-1.0)
    #define M 4000005
    #define inf 0x3f3f3f3f
    #define mod 1000000007
    #define IN inline
    #define W(a) while(a)
    #define lowbit(a) a&(-a)
    #define left k<<1
    #define right k<<1|1
    #define lson L, mid, left
    #define rson mid + 1, R, right
    #define ms(a,b) memset(a,b,sizeof(a))
    #define Abs(a) (a ^ (a >> 31)) - (a >> 31)
    #define random(a,b) (rand()%(b+1-a)+a)
    #define false_stdio ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    
    int n, cnt, Q;
    int  num[M];
    int T[M], Ls[M], Rs[M], sum[M];
    
    IN int Built(int L, int R) {
        int rt = ++cnt;
        if (L < R) {
            int mid = (L + R) >> 1;
            Ls[rt] = Built(L, mid);
            Rs[rt] = Built(mid + 1, R);
        }
        return rt;
    }
    
    IN int updata(int L, int R, int pre, int id) {
        int rt = ++cnt;
        Ls[rt] = Ls[pre], Rs[rt] = Rs[pre], sum[rt] = sum[pre] + 1;
        if (L < R) {
            int mid = (L + R) >> 1;
            if (id <= mid)Ls[rt] = updata(L, mid, Ls[pre], id);
            else Rs[rt] = updata(mid + 1, R, Rs[pre], id);
        }
        return rt;
    }
    
    
    //Rtot是上一个节点的右子节点的个数
    IN int query(int u, int v, int L, int R, int Rtot) {
        if (L == R)return L;
        int R_sum = sum[Rs[v]] - sum[Rs[u]];//右子节点的个数
        int mid = (L + R) >> 1;
        //判定条件
        if (mid - Rtot + 1 > R_sum)return query(Ls[u], Ls[v], L, mid, Rtot + R_sum);
        else return query(Rs[u], Rs[v], mid + 1, R, Rtot);
    }
    
    IN int read() {//读入挂
        int x = 0; bool f = 0; char ch = getchar();
        while (ch < '0' || '9' < ch)
            f |= ch == '-', ch = getchar();
        while ('0' <= ch && ch <= '9')
            x = x * 10 + ch - '0', ch = getchar();
        return f ? -x : x;
    }
    
    int main() {
        W(scanf("%d%d", &n, &Q) != EOF) {
            cnt = 0;
            T[0] = Built(1, n);
            for (register int i = 1; i <= n; i++)num[i] = read();
            for (register int i = 1; i <= n; i++)T[i] = updata(1, n, T[i - 1], num[i]);
    
            int l, r;
            W(Q--) {
                l = read(), r = read();
                printf("%d
    ", query(T[l - 1], T[r], 1, n, 0));
            }
        }
        return 0;
    }

            

  • 相关阅读:
    webpack学习最基本的使用方式(一)
    exports default 和export的使用方式
    vue兄弟组件之间的传值方式
    vue组件之间的传值方式
    vue组件创建学习总结
    vue实例生命周期钩子
    this 的工作原理
    node版本升级参考
    ES6 promise学习
    弹性布局学习总结
  • 原文地址:https://www.cnblogs.com/caibingxu/p/11617819.html
Copyright © 2020-2023  润新知