zoukankan      html  css  js  c++  java
  • 牛客小白月赛16 小石的妹子 二分 or 线段树

    牛客小白月赛16

    这个题目我AC之后看了一下别人的题解,基本上都是线段树,不过二分也可以。

    这个题目很自然就肯定要对其中一个进行排序,排完序之后再处理另外一边,另一边记得离散化。

    怎么处理呢,你仔细想想,找找规律就可以发现,其实我们就是在找递增子序列。

    第一次找到的就是重要程度为1 的妹子,然后删除这些元素,继续第二次找,第二次找到的就是重要程度为二的妹子。

    所以到每一个点,我们就只要根据它的大小来判断它应该放的位置(尽量靠前,并且小于这个数),然后更新这个位置,再返回这个位置,它所在的位置就是它的重要程度。

    emmm  其实就是用一个数组,数组的每一个位置 i 存的就是到目前位置重要程度为 i 的最大值。

    具体看代码吧。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <map>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn = 2e5 + 10;
    typedef long long ll;
    int num[maxn];
    map<ll, ll>mp;
    struct node
    {
        int l, r;
        int sum;
    }tree[4*maxn];
    struct edge
    {
        ll a, b, id, num, ans;
    }ex[maxn];
    
    bool cmp(edge a,edge b)
    {
        return a.a > b.a;
    }
    
    bool cmp1(edge a,edge b)
    {
        return a.b < b.b;
    }
    
    bool cmp2(edge a,edge b)
    {
        return a.id < b.id;
    }
    
    int tot = 0;
    int ok(ll x)
    {
        if (x > num[1]) return 1;
        if (x < num[tot])
        {
            tot++;
            return tot;
        }
        int l = 1, r = tot, ans = 0;
        int mid = (l + r) >> 1;
        while (l <= r) {
            int mid = (l + r) / 2;
            if (num[mid]<x) ans = mid, r = mid - 1;
            else l = mid + 1;
        }
        return ans;
    }
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%lld%lld", &ex[i].a, &ex[i].b), ex[i].id = i;
        }
        sort(ex + 1, ex + 1 + n, cmp1);
        for (int i = 1; i <= n; i++) mp[ex[i].b] = i;
        sort(ex + 1, ex + 1 + n, cmp);
        num[1] = mp[ex[1].b];
        ex[1].ans = 1;
        tot = 1;
        for(int i=2;i<=n;i++)
        {
            int f = ok(mp[ex[i].b]);
            // printf("%lld ex[%d]=%lld f=%d
    ",mp[ex[i].b], i, ex[i].b, f);
            num[f] = mp[ex[i].b];
            ex[i].ans = f;
        }
        sort(ex + 1, ex + 1 + n, cmp2);
        for (int i = 1; i <= n; i++) printf("%lld
    ", ex[i].ans);
        return 0;
    }
    二分

    网上的线段树的方法我感觉和逆序对有点像,就是首先还是把 b 离散化,然后对 a 进行排序,

    然后从 1 ~ n 遍历,如果对于每一个 b 首先判断 b ~ n 有没有值,其实就是有没有比 b 大的再前面放过了,有的话就去最大值,重要程度就是 最大值+1 (这个是因为存进去的就是最大值)

    没有那么重要程度就是 1 ,然后再更新这个点 b 把 b 的重要程度放到线段树的 b 这个位置以便后面的查询。

    这个很好写的。

    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <algorithm>
    #include <string>
    #include <iostream>
    #include <map>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    const int maxn = 2e5 + 10;
    typedef long long ll;
    map<ll, ll>mp;
    struct node
    {
        int l, r;
        int num;
    }tree[4*maxn];
    struct edge
    {
        ll a, b, id, num, ans;
    }ex[maxn];
    
    bool cmp(edge a,edge b)
    {
        return a.a > b.a;
    }
    
    bool cmp1(edge a,edge b)
    {
        return a.b < b.b;
    }
    
    bool cmp2(edge a,edge b)
    {
        return a.id < b.id;
    }
    
    void build(int id, int l, int r) {
        tree[id].l = l;
        tree[id].r = r;
        if (l == r) {
            tree[id].num = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(id << 1, l, mid);
        build(id << 1 | 1, mid + 1, r);
    }
    
    int query(int id, int x, int y) {
        int l = tree[id].l;
        int r = tree[id].r;
        if (x <= l && y >= r) {
            //    printf("id=%d sum=%d 
    ", id,tree[id].sum);
            return tree[id].num;
        }
        int ans = 0;
        int mid = (l + r) >> 1;
        if (x <= mid) ans = max(ans, query(id << 1, x, y));
        if (y > mid) ans = max(ans, query(id << 1 | 1, x, y));
        //    printf("id=%d ans=%d l=%d r=%d x=%d y=%d 
    ", id, ans, l, r,x,y);
        return ans;
    }
    
    void push_up(int id) {
        tree[id].num = max(tree[id << 1].num , tree[id << 1 | 1].num);
    }
    
    void update(int id, int x,int val) {
        int l = tree[id].l;
        int r = tree[id].r;
        if (l == r) {
            tree[id].num = val;
            return;
        }
        int mid = (l + r) >> 1;
        if (x <= mid) update(id << 1, x,val);
        else update(id << 1 | 1, x,val);
        push_up(id);
    }
    
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%lld%lld", &ex[i].a, &ex[i].b), ex[i].id = i;
        }
        sort(ex + 1, ex + 1 + n, cmp1);
        for (int i = 1; i <= n; i++) mp[ex[i].b] = i;
        sort(ex + 1, ex + 1 + n, cmp);
        build(1, 1, n);
        for(int i=1;i<=n;i++)
        {
            int f = query(1, mp[ex[i].b], n) + 1;
            ex[i].ans = f;
            update(1, mp[ex[i].b],f);
        }
        sort(ex + 1, ex + 1 + n, cmp2);
        for (int i = 1; i <= n; i++) printf("%lld
    ", ex[i].ans);
        return 0;
    }
    逆序对 线段树
  • 相关阅读:
    最新国家标准下载(2020-7-31)
    SL/T 264-2020 水利水电工程岩石试验规程
    SH/T 3082-2019 石油化工仪表供电设计规范
    GB/T 4780-2020 汽车车身术语
    Java——冒泡排序
    JSP处理XML数据
    JSP标准标签库(JSTL)
    千锤百炼软工第十九天
    千锤百炼软工第十八天
    千锤百炼软工第十七天
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11201051.html
Copyright © 2011-2022 走看看