• Check List线段树维护偏序三元组


    下面这个题是二维偏序问题
    所谓偏序问题,是指多约束条件的元素统计等问题
    如下:
    题目链接

    Check List

    题目描述

    When test driving a vehicle, you are asked to make a checkmark on a tablet. Upon inspection, you have noticed many fingerprints on the screen. Aside from the rush of disgust, you notice that the fingerprints on the screen can be represented by a series of 2D points on a standard Cartesian grid. You know that checkmarks can be uniquely defined by three points; these three points have distinct x coordinates and the three points also have distinct y coordinates. The leftmost point must be lower than the rightmost point and higher than the middle point. Now you want to know how many unique checkmarks you can make using the 2D points.

    Let’s consider some examples. The three points (1,2), (2,1), and (3,2) do not form a valid checkmark because the leftmost and rightmost points are at the same height. The three points (1,2), (2,1), and (2,3) do not form a valid checkmark because two points have the same x coordinates. The three points (1,2), (3,1), and (4,9) do form a valid checkmark.

    Given a list of 2D points, determine the number of unique checkmarks that can be formed from them.

    输入描述:

    The first input line contains a single integer, n (1 ≤ n ≤ 100,000), representing the number of points. Each of the following n input lines contains two integers, xi and yi (1 ≤ xi, yi ≤1,000,000,000), representing the location of a point on the 2D grid. No two points will be identical.

    输出描述:

    Print the number of distinct checkmarks that can be formed by the given 2D points.

    示例1

    输入

    6 
    6 6
    5 3
    1 5
    3 2
    4 4
    2 1
    

    输出
    5

    示例2

    输入

    10
    4 2
    9 4
    1 5
    2 4
    10 5
    6 1
    3 3
    8 3
    5 1
    7 2
    

    输出
    20

    如上的问题是让求出满足三元组(xi,yi),(xj,yj)(xk,yk)
    且{
    xi < xj < xk
    yj < yi < yk
    }的数量
    这里的约束条件有两个,可以称作是二维偏序问题

    推荐一篇博客:链接
    这里面总结了一些经验
    关于这个题目,学长的博客链接里面讲到了一些做题的思路:
    按照x坐标进行排序,然后对y进行离散化处理(看数据范围就会发现y的数据范围达到了1e9,但是最多只会有2e5个点)
    之后,假设当前位置是pos
    考虑当前位置作为第二个的贡献,即对所有之前出现过的数 大于h[pos]的+1
    然后再加上pos作为第三个数的贡(即对答案的贡献)
    所以你需要维护两个操作:
    1.对所有出现过的数,在[x,y]区间内都+1
    2.求所有出现过的数,在[x,y]区间内的权值
    因为题目要求出现过,所以用线段树再次维护一个b权值,代表当前节点下,出现了多少个点
    那么lazy 向下传 就不传 区间长度了 而是b[k]
    每次单点修改时,将lazy传递下来,这样就不会影响新的lazy传递

    /*** keep hungry and calm PushyTao!***/
    #define PI (double)acos(-1.0)
    #define md tree[rt].l+tree[rt].r>>1
    typedef int itn;
    vector<ll> vet;
    struct node{
        int x,y;
        friend bool operator <(node a,node b){
            if(a.x != b.x) return a.x < b.x;
            else return a.y < b.y;
        }
    }a[maxn];
    struct SegmentTree{
        int l,r;
        ll sum1,sum2,lazy;
    }tree[maxn<<2];
    void PushUp(int rt){
        tree[rt].sum1 = tree[rt << 1].sum1 + tree[rt << 1 | 1].sum1;
        tree[rt].sum2 = tree[rt << 1].sum2 + tree[rt << 1 | 1].sum2;
    }
    void PushDown(int rt){
        if(tree[rt].lazy){
            tree[rt << 1].sum2 += tree[rt << 1].sum1 * tree[rt].lazy;
            tree[rt << 1 | 1].sum2 += tree[rt << 1 | 1].sum1 * tree[rt].lazy;
            tree[rt << 1].lazy += tree[rt].lazy;
            tree[rt << 1 | 1].lazy += tree[rt].lazy;
            tree[rt].lazy = 0;
        }
    }
    void Build(int rt,int l,int r){
        tree[rt].l = l;
        tree[rt].r = r;
        tree[rt].sum1 = tree[rt].sum2 = tree[rt].lazy = 0;
        if(l == r) return ;
        int mid = l + r >> 1;
        Build(rt << 1,l,mid);
        Build(rt << 1 | 1,mid + 1,r);
    }
    void UpdatePnt(int rt,int pos){
        if(tree[rt].l == tree[rt].r && tree[rt].r == pos){
            ++ tree[rt].sum1;
            return ;
        }
        PushDown(rt);
        ///int mid = md;
        if(pos <= md) UpdatePnt(rt << 1,pos);
        else UpdatePnt(rt << 1 | 1,pos);
        PushUp(rt);
    }
    void Update(int rt,int l,int r){
        if(tree[rt].r < l || tree[rt].l > r) return ;
        if(tree[rt].l >= l && tree[rt].r <= r){
            tree[rt].sum2 += tree[rt].sum1;
            ++ tree[rt].lazy;
            return ;
        }
        PushDown(rt);
        Update(rt << 1,l,r);
        Update(rt << 1 | 1,l,r);
    }
    ll Query(int rt,int l,int r){
        if(tree[rt].r < l || tree[rt].l > r) return 0LL;
        if(tree[rt].l >= l && tree[rt].r <= r){
            return tree[rt].sum2;
        }
        PushDown(rt);
        return Query(rt << 1,l,r) + Query(rt << 1 | 1,l,r);
    }
    int id(ll x){
        return lower_bound(vet.begin(),vet.end(),x) - vet.begin() + 1;
    }
    int main() {
        int n = read;
        for(int i=1;i<=n;i++){
            a[i].x = read,a[i].y = read;
            vet.push_back(a[i].y);
        }
        sort(a+1,a+1+n);
        sort(vet.begin(),vet.end());
        vet.erase(unique(vet.begin(),vet.end()),vet.end());
        int siz = vet.size();
        Build(1,1,siz);///total number of element is size
        ll ret = 0;
        for(int i=1;i<=n;i++){
            int p = i;
            while(p <= n && a[p].x == a[i].x){
                int _id = id(a[p].y);
                ret += Query(1,1,_id-1);
                ++ p;
            }
            p = i;
            while(p <= n && a[p].x == a[i].x){
                int _id = id(a[p].y);
                Update(1,_id+1,siz);
                ++ p;
            }
            p = i;
            while(p <= n && a[p].x == a[i].x){
                int _id = id(a[p].y);
                UpdatePnt(1,_id);
                ++ p;
            }
            i = p - 1;
        }
        cout << ret <<endl;
    	return 0;
    }
    /**
    
    
    
    
    **/
    
    
  • 相关阅读:
    python调用linux DBus
    python查看单个应用的内存
    Azkaban
    H2 数据库引擎
    【IDEA与sql执行计划】
    【用draw.io 绘制ER图,非鸭蛋型ER图~】
    MySQL&Oracle数据库进阶学习【未完】
    【关于Typora 在线图床配置】
    什么是文件描述符
    同步个人vs code 习惯性配置 到码云(Gitee)
  • 原文地址:https://www.cnblogs.com/PushyTao/p/15101039.html
Copyright © 2020-2023  润新知