[SHOI2007]园丁的烦恼(离散化,树状数组)

[SHOI2007]园丁的烦恼(luogu)

Solution

发现坐标范围很大,考虑离散化

但离散之后还是不能用二维数据结构,数组大小太大

发现没有修改,只有查询

可以考虑 x 坐标依次增大时,只记录 y 坐标的信息

于是把询问分成四个以(0,0)为左下角的询问,依次算出再汇总

将 每个询问的坐标 和 树的坐标 放在一个数组中,离散化 y 坐标

按 x 坐标从小到大排序,x 坐标相等时树在前面,询问在后面

遍历数组,碰到树时树状数组中它的 y 坐标加 1

碰到询问时求树状数组中小于等于它的 y 坐标的和即可

Code

 

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int N=3e6+10;
int tr[N],n,m,cnt,A,B,C,D,ans[N],tot;
struct node
{
    int x,id;
    bool operator <(const node &o)const
    {
        return x<o.x;
    }
}a[N];
struct mode
{
    int x,y,id,inv;
    bool operator <(const mode &o)const
    {
        return x==o.x?id<o.id:x<o.x;
    }
}d[N];
int lowbit(int x)
{
    return x&(-x);
}
int get(int x)
{
    int ans=0;
    for(;x;x-=lowbit(x)) ans+=tr[x];
    return ans;
}
void add(int x)
{
    for(;x<=cnt;x+=lowbit(x)) tr[x]++;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        tot++;
        scanf("%d%d",&d[tot].x,&d[tot].y);
        d[tot].x++,d[tot].y++;
        d[tot].id=0;
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&A,&B,&C,&D);
        A++,B++,C++,D++;
        d[++tot]=(mode){A-1,B-1,i,1};
        d[++tot]=(mode){C,D,i,1};
        d[++tot]=(mode){A-1,D,i,-1};
        d[++tot]=(mode){C,B-1,i,-1};
    }
    for(int i=1;i<=tot;i++)
        a[i].x=d[i].y,a[i].id=i;
    sort(a+1,a+1+tot);
    for(int i=1;i<=tot;i++)
    {
        if(i==1 || a[i].x!=a[i-1].x) cnt++;
        d[a[i].id].y=cnt;
    }
    sort(d+1,d+1+tot);
    for(int i=1;i<=tot;i++)
    {
        if(d[i].id) ans[d[i].id]+=d[i].inv*get(d[i].y);
        else add(d[i].y);
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

 

 

 

猜你喜欢

转载自www.cnblogs.com/hsez-cyx/p/12418199.html