HDU 5517 (ACM 2015 沈阳) Triple [树状数组]

题意:给你N个二元组,M个三元组,在二元组与三元组的最后一个数相同时,两者去掉最后一个数,用剩下的三个数拼凑出一个新的三元组<X,Y,Z>,求这些三维坐标的上凸面的点数。

范围:N,M<=10W,拼凑出来的三元组的X,Y,Z的X<=10W,Y,Z<=1000

解法:很容易发现Y,Z的坐标很小,即变成了求按X排序后,求Y,Z右上方是否还有点,如果没有点了,说明这个点是上凸的点。这个过程可以用二维树状数组完成。当然之前有一个贪心过程,就是对应最后一个数相同的时候,X要取前面二元组中最大的,且需要记录一下取最大值的二元组的数量,最后一旦发现点上凸,加上这个记录的数量即可。

代码:

注意代码中的<X,Y,Z>对应着题目意思的<Y,Z,X>,为了少写一个重载orz

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<iostream>
#include<stdlib.h>
#include<set>
#include<map>
#include<queue>
#include<vector>
#include<bitset>
#pragma comment(linker, "/STACK:1024000000,1024000000")
template <class T>
bool scanff(T &ret){ //Faster Input
    char c; int sgn; T bit=0.1;
    if(c=getchar(),c==EOF) return 0;
    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();
    sgn=(c=='-')?-1:1;
    ret=(c=='-')?0:(c-'0');
    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');
    if(c==' '||c=='\n'){ ret*=sgn; return 1; }
    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;
    ret*=sgn;
    return 1;
}
#define inf 1073741823
#define llinf 4611686018427387903LL
#define PI acos(-1.0)
#define lth (th<<1)
#define rth (th<<1|1)
#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)
#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)
#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)
#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)
#define mem(x,val) memset(x,val,sizeof(x))
#define mkp(a,b) make_pair(a,b)
#define findx(x) lower_bound(b+1,b+1+bn,x)-b
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
#define lowbit(x) (x&(-x))
#define NN 100100
struct node{
    int x,y,z,cot;
    bool operator < (const node temp)const{
        return z<temp.z;
    }
}a[NN],b[NN];
int n,m;
int la[NN],ra[NN],lb[NN],rb[NN];
int c[1010][1010];

void add(int i,int j){
    for(int x=i;x<=1000;x+=lowbit(x))
    for(int y=j;y<=1000;y+=lowbit(y)){
        c[x][y]++;
    }
}
int getsum(int i,int j){
    int sum=0;
    for(int x=i;x>0;x-=lowbit(x))
    for(int y=j;y>0;y-=lowbit(y)){
        sum+=c[x][y];
    }
    return sum;
}

map<pii,int> mp;
int main(){
    tdata{
        scanff(n);scanff(m);
        rep(i,1,n){
            scanff(a[i].y);
            scanff(a[i].z);
        }
        rep(i,1,m){
            scanff(b[i].x);
            scanff(b[i].y);
            scanff(b[i].z);
            b[i].x=1001-b[i].x;
            b[i].y=1001-b[i].y;
        }
        sort(a+1,a+1+n);
        sort(b+1,b+1+m);
        mem(la,0);mem(ra,0);mem(lb,0);mem(rb,0);mem(c,0);
        rep(i,1,n){
            if(i==1||a[i].z!=a[i-1].z)la[a[i].z]=i;
            if(i==n||a[i].z!=a[i+1].z)ra[a[i].z]=i;
        }
        rep(i,1,m){
            if(i==1||b[i].z!=b[i-1].z)lb[b[i].z]=i;
            if(i==m||b[i].z!=b[i+1].z)rb[b[i].z]=i;
        }
        rep(i,1,100000){
            if(lb[i]==0)continue;
            if(la[i]==0){
                rep(j,lb[i],rb[i]){
                    b[j].z=0;
                    b[j].cot=0;
                }
                continue;
            }
            int maxx=-inf,cot=0;
            rep(j,la[i],ra[i]){
                if(a[j].y==maxx)cot++;
                else if(a[j].y>maxx){
                    cot=1;
                    maxx=a[j].y;
                }
            }
            rep(j,lb[i],rb[i]){
                b[j].z=maxx;
                b[j].cot=cot;
            }
        }
        sort(b+1,b+1+m);
        ll ans=0;
        drep(i,m,1){
            if(i==1||b[i].z!=b[i-1].z){
                mp.clear();
                rep(j,i,m){
                    mp[mkp(b[j].x,b[j].y)]++;
                    add(b[j].x,b[j].y);
                    if(j==m||b[j].z!=b[j+1].z)break;
                }
                rep(j,i,m){
                    if(getsum(b[j].x,b[j].y)-mp[mkp(b[j].x,b[j].y)]==0){
                        ans+=ll(b[j].cot);
                    }
                    if(j==m||b[j].z!=b[j+1].z)break;
                }
            }
        }
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值