P2163 [SHOI2007]园丁的烦恼

题目

P2163 [SHOI2007]园丁的烦恼

做法

关于拆点,要真想拆直接全部用树状数组水过不就好了

做这题我们练一下\(cdq\)分治

左下角\((x1,y1)\)右上角\((x2,y2)\),查询\(x1≤x≤x2\)&&\(y1≤y≤y2\)的个数
假设点(x,y)为矩形\((x,y)(x,y)\)
其实我们要查询的是\(x1≤x,x2≥x,y1≤y≤y2\)

初始化排序\(x\)降序排,去掉\(x1≤x\),树状数组限制\(x≤x2\),区间查询\(y1≤y≤y2\),就是一三维偏序

讲一下排序吧:
由于我们要查询\(x1≤x\),所以初始化排序\(x\)降序排,\(x1\)我们就不管了
升序排\(x2\)然后进树状数组,\(y2\)其实没用(区间查询就卡过去了)
\(y1≤y\)由于这部分不好直接处理每个点结构体\(y1=y\)然后升序排
最后由于重复点也要计算我们另点的\(y2\),由于查询的\(y2\)有值,\(y2\)升序排,让查询在前

My complete code

常数贼大的代码,还没某dalao不离散跑得快

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<string>
#include<vector>
using namespace std;
typedef int LL;
const LL maxn=2e6;
inline LL Read(){
    LL x(0),f(1);char c=getchar();
    while(c<'0'||c>'9'){
        if(c=='-')f=-1;c=getchar();
    }
    while(c>='0'&&c<='9')
        x=(x<<3)+(x<<1)+c-'0',c=getchar();
    return x*f;
}
struct node{
    LL x1,y1,x2,y2,id,val;
}a[maxn];
LL n,m,tot1,tot2;
LL tree[maxn],ans[maxn],x[maxn],y[maxn];
inline bool cmp2(node g1,node g2){
    return g1.x2==g2.x2?(g1.y1==g2.y1?g1.y2<g2.y2:g1.y1>g2.y1):g1.x2<g2.x2;
}
inline bool cmp1(node g1,node g2){
    return (g1.x1^g2.x1)?g1.x1>g2.x1:cmp2(g1,g2);
}
inline LL Lowbit(LL x){
    return x&(-x);
}
inline void Add(LL x,LL val){
    for(;x<=tot2;x+=Lowbit(x))
        tree[x]+=val;
}
inline LL Query(LL x){
    LL ret(0);
    for(;x;x-=Lowbit(x))
        ret+=tree[x];
    return ret;
}
void Cdq(LL l,LL r){
    if(l==r)
        return;
    LL mid(l+r>>1);
    Cdq(l,mid),Cdq(mid+1,r),
    sort(a+l,a+1+mid,cmp2),sort(a+mid+1,a+1+r,cmp2);
    LL j(l-1);
    for(LL i=mid+1;i<=r;++i){
        while(j<mid&&a[j+1].x2<=a[i].x2)
            Add(a[j+1].y1,a[j+1].val),++j;
        ans[a[i].id]+=Query(a[i].y2)-Query(a[i].y1-1);
    }
    for(LL i=l;i<=j;++i)
        Add(a[i].y1,-a[i].val);
}
int main(){
    n=Read(),m=Read();
    for(LL i=1;i<=n;++i)
        x[++tot1]=a[i].x1=Read()+1,
        y[++tot2]=a[i].y1=Read()+1,
        a[i].val=1;
    for(LL i=1;i<=m;++i){
        LL now(n+i);
        x[++tot1]=a[now].x1=Read()+1,
        y[++tot2]=a[now].y1=Read()+1,
        x[++tot1]=a[now].x2=Read()+1,
        y[++tot2]=a[now].y2=Read()+1,
        a[now].id=i;
    }
    sort(x+1,x+1+tot1),sort(y+1,y+1+tot2),
    tot1=unique(x+1,x+1+tot1)-x-1,tot2=unique(y+1,y+1+tot2)-y-1;
    for(LL i=1;i<=n;++i)
        a[i].x2=a[i].x1=lower_bound(x+1,x+1+tot1,a[i].x1)-x,
        a[i].y1=lower_bound(y+1,y+1+tot2,a[i].y1)-y;
    for(LL i=1;i<=m;++i){
        LL now(n+i);
        a[now].x1=lower_bound(x+1,x+1+tot1,a[now].x1)-x,
        a[now].y1=lower_bound(y+1,y+1+tot2,a[now].y1)-y,
        a[now].x2=lower_bound(x+1,x+1+tot1,a[now].x2)-x,
        a[now].y2=lower_bound(y+1,y+1+tot2,a[now].y2)-y;
    }
    n+=m,
    sort(a+1,a+1+n,cmp1),
    Cdq(1,n);
    for(LL i=1;i<=m;++i)
        printf("%d\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/y2823774827y/p/10285597.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值