【JZOJ A组】hole

本文介绍了一种解决四维偏序问题的方法,通过构建等腰直角三角形并查询内部洞的数量来帮助GFS避免DSJ的破坏。文章详细展示了如何利用离线查询、时间复杂度优化技巧及树状数组进行高效处理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Description

GFS打算去郊外建所别墅,享受生活,于是他耗费巨资买下了一块风水宝地,但令他震惊的是,一群DSJ对GFS的富贵生活深恶痛绝,决定打洞以搞破坏。
现在我们简化一下这个问题,在这片土地上会按顺序发生一系列事件。
①一只DSJ在(x,y) 这个点打了一个洞。
②有着高雅品味GFS想建一个等腰直角三角形的别墅,即由(x,y) ,(x+d,y) ,(x,y+d) 三点围成的三角形,但为了地基的牢固,他想知道当前这块三角形土地内的洞的个数。
GFS现在对DSJ已经忍无可忍了,请你帮他回答这些询问。
初始土地上没有洞。GFS毕竟是GFS,你可以认为土地无限大。

Input

第一行一个整数 n,表示事件数。接下来n行,每行3个非负整数x ,y ,d 。
若d=0 表示DSJ打洞的事件。否则表示GFS建房的询问。

Output

对每个询问输出一个整数,表示当时询问的三角形内的洞的个数。

Sample Input

输入1:
8
1 3 0
1 5 0
3 6 0
4 4 0
2 6 0
1 5 3
1 5 4
1 1 1
输入2:
4
1 5 0
3 7 0
2 5 6
2 3 4

Sample Output

输出1:
3
3
0
输出2:
1
0

Data Constraint

30%的数据n<=3333 。
另30% 的数据 GFS只会在DSJ打完洞后才开始询问,xi,yi<=333333 。
100%的数据 1<=n<=88888,xi,yi<=3333333 。

思路

四维偏序问题
时间、x、y三维,再加上这个点是否在三角形内,即x1+y1

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+77;
struct A
{
    int x,y,z,w;
}a[maxn],b[maxn],b1[maxn],b2[maxn];
int s[3333377],ans[maxn],mx,cnt,t,sum,n;
bool cmp(A x,A y)
{
    return x.z<y.z||x.z==y.z&&x.w<y.w;
}
bool cmp1(A x,A y)
{
    return x.x<y.x;
}
int lowbit(int x)
{
    return x&-x;
}
void insert(int x,int d)
{
    sum+=d;
    for(; x<=mx; x+=lowbit(x)) s[x]+=d;
}
int query(int x)
{
    int p=0;
    for(; x; x-=lowbit(x)) p+=s[x];
    return sum-p;
}
void cdq2(int l,int r)
{
    if(l==r) return;
    int mid=(l+r)>>1,cnt1=0,cnt2=0;
    cdq2(l,mid); cdq2(mid+1,r);
    for(int i=l; i<=mid; i++) if(!b[i].w) b1[++cnt1]=b[i];
    for(int i=mid+1; i<=r; i++) if(b[i].w) b2[++cnt2]=b[i];
    if(!cnt1||!cnt2) return;
    sort(b1+1,b1+cnt1+1,cmp1); sort(b2+1,b2+cnt2+1,cmp1);
    int j=cnt1+1;
    for(int i=cnt2; i>=1; i--)
    {
        while(j>1&&b1[j-1].x>=b2[i].x) insert(b1[--j].y,1);
        ans[b2[i].w]+=query(b2[i].y-1);
    }
    for(int i=j; i<=cnt1; i++) insert(b1[i].y,-1);
}
/*void cdq2(int l,int r)
{
    if (l==r) return;
    int mid=(l+r)/2,cnt1=0,cnt2=0;
    cdq2(l,mid),cdq2(mid+1,r);
    for (int i=l; i<=mid;i++) if (!b[i].w) b1[++cnt1]=b[i];
    for (int i=mid+1;i<=r;i++) if (b[i].w) b2[++cnt2]=b[i];
    if (!cnt1||!cnt2) return;
    sort(b1+1,b1+cnt1+1,cmp1),sort(b2+1,b2+cnt2+1,cmp1);
    int k=cnt1+1;
    for (int i=cnt2;i>=1;i--)
    {
        while (k>1&&b1[k-1].x>=b2[i].x) insert(b1[--k].y,1),printf("%d 1\n",b1[k].y);
        ans[b2[i].w]+=query(b2[i].y-1);
    }
    for (int i=k;i<=cnt1;i++) insert(b1[i].y,-1),printf("%d -1\n",b1[i].y);
}*/

void cdq(int l,int r)
{
    if (l==r) return;
    int mid=(l+r)>>1;
    cdq(l,mid),cdq(mid+1,r);
    int cnt=0,boo=0;
    for (int i=l; i<=mid; i++) if (!a[i].w) b[++cnt]=a[i];
    for (int i=mid+1; i<=r; i++) if (a[i].w) b[++cnt]=a[i],boo=1;
    if (!boo||!cnt) return;
    sort(b+1,b+cnt+1,cmp); cdq2(1,cnt);
}
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        int x,y,d;
        scanf("%d%d%d",&x,&y,&d);
        a[i].x=x; a[i].y=y; a[i].z=x+y+d; mx=max(mx,y+d);
        if(d) a[i].w=++t;
    }
    cdq(1,n);
    for(int i=1; i<=t; i++) printf("%d\n",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值