2011珠海赛--Minimal Elements(线段树)

Description

 Given a partial order (P, <=). Every element pi of set P is a vector of three integers: (xi, yi, zi). Say pi <= pj iff xi <= xj and yi <= yj and zi<=zj. An element pi is called a minimal element of P iff no element of P except pi itself <= pi. Your task is to find out all minimal elements of P.

Input

 There are multiple test cases.

The first line of each case is an integer n (0 < n <= 100000), indicating the size of set P. n lines follow. The (i+1)th line is three 32-bit signed integers xi, yi and zi, indicating pi of P. All vectors are distinct.
Input is terminated by EOF.
Output

 For each test case, print the number of minimal elements of P in a line.

Sample Input
 Copy sample input to clipboard
3
3 3 3
1 2 4
2 4 6
2
1 1 1
2 0 2
Sample Output
2
2
题意:求有多少个三元组,使得所给三元组中不存在一个三元组使得xi<=x,yi<=y,zi<=y.
思路:按X轴从小到大,y轴从小到大,z轴从小到大排序。将3维降为2维。然后离散化y轴。建立线段树,维护区间最小值。
先将3元组按x从小到大排序,y从小到大排序,z从小到大排序。因为不会出现完全一致的3元组。所以这样排序之后,后来的三元组不可能让之前的三元组失去最小的性质。只有可能前面的让后面的失去最小的性质。前面的x我们排序后肯定是>=后来的三元组的x。只用考虑y和z。因为y比较大,我们将y离散化然后建立线段树。线段树存一个区间最小值,也就是区间最小的z值。这样每一进来一个三元组,我们就找到他对应的y在线段树上的位置,然后看这一段的最小z是不是<=这个三元组的z。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define maxn 100080
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define inf 0x3f3f3f3f3f3f3f3fll
#define LL long long int
int Y[maxn];
struct ST
{
    int l,r;
    LL minz;
}st[maxn<<2];

void buildtree(int id,int l,int r)
{
    st[id].l = l,st[id].r = r;
    st[id].minz = inf;
    if(l == r)  return;
    int mid = (l+r) >> 1;
    buildtree(lson);
    buildtree(rson);
}

void PushUp(int id)
{
    st[id].minz = min(st[id<<1].minz,st[id<<1|1].minz);
}
//如果没有人把他淘汰,那才用更新
void Update(int id,int pos,int newz)
{
    if(st[id].l == pos && st[id].r == pos)
    {
        st[id].minz = newz;
        return;
    }
    if(st[id<<1].r >= pos)
        Update(id<<1,pos,newz);
    else Update(id<<1|1,pos,newz);
    PushUp(id);
}

//询问l到r的最小值
LL query(int id,int l,int r)
{
    if(st[id].l == l && st[id].r == r)
        return st[id].minz;
    if(st[id<<1].r >= r)
        return query(id<<1,l,r);
    else if(st[id<<1|1].l <= l)
        return query(id<<1|1,l,r);
    else return min(query(id<<1,l,st[id<<1].r),query(id<<1|1,st[id<<1|1].l,r));
}

struct Item
{
    int x,y,z;
    bool operator < (const Item & a)const
    {
        if(x != a.x)    return x < a.x;
        else if(y != a.y)   return y < a.y;
        else return z < a.z;
    }
}item[maxn];

int main()
{
   // freopen("in.txt","r",stdin);
    
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        //cout << inf << endl;
        for(int i = 1;i <= n;i++)
        {
            scanf("%d%d%d",&item[i].x,&item[i].y,&item[i].z);
            Y[i] = item[i].y;
        }
        sort(item+1,item+1+n);
        sort(Y+1,Y+1+n);
        buildtree(1,1,n);
        int ans = n;
        for(int i = 1;i <= n;i++)
        {
            int pos = lower_bound(Y+1,Y+1+n,item[i].y) - Y;
            LL z = query(1,1,pos);
            if(z <= item[i].z)
            {
                ans--;
                continue;
            }
            else Update(1,pos,item[i].z);
        }
        printf("%d\n",ans);
    }
    return 0;
    
}                                 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值