JZOJ4419. 【GDOI2016模拟4.2】hole

18 篇文章 0 订阅
1 篇文章 0 订阅

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 。

题解

这个是个三维偏序问题,
时间还有二维平面。

这种问题一般是用cdq分治处理掉时间,
然后再二维平面上面用树套树维护。
而这里是要维护一个三角形,并不是常见的四边形。
其实可以把等腰三角形拆开来,拆成一个直角梯形,另一腰围45度,和一个长方形,
于是这样就可以解决了。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{
    n=0;
    ch=G();
    while((ch<'0' || ch>'9') && ch!='-')ch=G();
    ll w=1;
    if(ch=='-')w=-1,ch=G();
    while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();
    n*=w;
}

void write(ll x){if(x>9) write(x/10);P(x%10+'0');}

struct node
{
    int id,z,x,y,t;
}a[N*2],t[N*2];

bool cmp(node a,node b)
{
    return a.y<b.y;
}

int n,ans[N],m,q;
int x[N],y[N],d[N],s[10000003];

int x_(int x){return x&(-x);}

void ins(int x,int z)
{
    for(int i=x;i<=m;i=i+x_(i))
        s[i]=s[i]+z;
}

int find(int x)
{
    int t=0;
    for(int i=x;i;i=i-x_(i))
        t=t+s[i];
    return t;
}

void solve(int l,int r)
{
    if(l==r)return;
    int mid=(l+r)>>1;
    for(int i=l,s1=l,s2=mid+1;i<=r;i++)
        if(a[i].x<=mid)t[s1++]=a[i];else t[s2++]=a[i];
    for(int i=l;i<=r;i++)a[i]=t[i];
    solve(l,mid);
    for(int i=l,j=mid+1;j<=r;j++)
    {
        for(;i<=mid && a[i].y<=a[j].y;i++)
            if(a[i].t==0)ins(a[i].z,1);

        if(a[j].t)ans[a[j].id]=ans[a[j].id]+find(a[j].z)*a[j].t;

        if(j==r)
        {
            for(;i>l;)
                if(a[--i].t==0)ins(a[i].z,-1);
        }
    }
    solve(mid+1,r);
    sort(a+l,a+r+1,cmp);
}

int main()
{
    read(n);
    for(int i=1;i<=n;i++)
        read(x[i]),read(y[i]),read(d[i]),m=max(m,x[i]+y[i]+d[i]);

    for(int i=1;i<=n;i++)
        if(d[i]==0)
        {
            q++;
            a[q].z=x[i]+y[i];
            a[q].x=q;
            a[q].y=x[i];
            a[q].id=i;
            a[q].t=0;
        }
        else
        {
            q++;
            a[q].z=x[i]+y[i]+d[i];
            a[q].x=q;
            a[q].y=x[i]-1;
            a[q].id=i;
            a[q].t=-1;

            q++;
            a[q].z=x[i]+y[i]+d[i];
            a[q].x=q;
            a[q].y=x[i]+d[i];
            a[q].id=i;
            a[q].t=1;
        }

    sort(a+1,a+1+q,cmp);
    solve(1,q);

    q=0;
    for(int i=1;i<=n;i++)
        if(d[i]==0)
        {
            q++;
            a[q].z=y[i];
            a[q].x=q;
            a[q].y=x[i];
            a[q].id=i;
            a[q].t=0;
        }
        else
        {
            q++;
            a[q].z=y[i]-1;
            a[q].x=q;
            a[q].y=x[i]-1;
            a[q].id=i;
            a[q].t=1;

            q++;
            a[q].z=y[i]-1;
            a[q].x=q;
            a[q].y=x[i]+d[i];
            a[q].id=i;
            a[q].t=-1;
        }
    sort(a+1,a+1+q,cmp);
    solve(1,q);

    for(int i=1;i<=n;i++)
        if(d[i])write(ans[i]),P('\n');

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值