P2163 【[SHOI2007]園丁的煩惱】

實際上是不用把一個詢問拆成四個的

把詢問轉化爲數學語言:

對於每一個查詢,詢問知足$a<=x<=b$且$c<=y<=d$的點$x,y$的個數

~~天然~~想到偏序問題,看到有兩個式子,二維偏序?好像辦不到,反正我不會

如何升維,拆分便可

把原式拆成$a<=x,x<=b,c<=y,y<=d$,這樣就能夠用四維偏序解決了,可是這樣的複雜度顯然是不能保證的

嘗試降維

若是這樣呢$a<=x,x<=b,c<=y<=d$

對於一個點,咱們定義其三個維度爲:

$a,b->x$即以橫座標做爲第一維和第二維

$c->y$即以縱座標做爲第三維

而查詢,依照上式,咱們定義其維度

以$a$爲第一維,$c$爲第二維,$b,d$爲三維和四維(查詢用)

因此三維偏序的式子就是

$a_i<=a_j,b_i>=b_j,c_i<=c_j<=d_i$

考慮重複元素的貢獻問題,記得排序時加上$c$相同,按$d$排

上代碼(實際上是要寫離散化的,可是我懶得寫,拿$O2$替了)

node

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=5e5+10,maxl=1e7+10;
struct node{
    int a,b,c,d,w,mp;
}v[2*maxn];
int n,m,c[maxl],ans[maxn];
bool cmpy(const node &a,const node &b)
{
    return a.b==b.b?(a.c==b.c?a.d<b.d:a.c>b.c):a.b<b.b;
}
bool cmpx(const node &a,const node &b)
{
    return a.a==b.a?cmpy(a,b):a.a>b.a;
}
int lowbit(int x)
{
    return x&-x;
}
void add(int x,int ch)
{
    while(x<=maxl-9)
    {
        c[x]+=ch;
        x+=lowbit(x);
    }
}
int sum(int x)
{
    int ret=0;
    while(x)
    {
        ret+=c[x];
        x-=lowbit(x);
    }
    return ret;
}
void cdq(int l,int r)
{
    if(l==r)
        return;
    int mid=l+r>>1;
    cdq(l,mid),cdq(mid+1,r);
    sort(v+l,v+mid+1,cmpy),sort(v+mid+1,v+r+1,cmpy);
    int i=l,j=mid+1;
    for(;j<=r;j++)
    {
        while(v[i].b<=v[j].b&&i<=mid)
            add(v[i].c,v[i].w),i++;
        ans[v[j].mp]+=sum(v[j].d)-sum(v[j].c-1);
    }
    for(j=l;j<i;j++)
        add(v[j].c,-v[j].w);
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&v[i].a,&v[i].c);
        v[i].a++,v[i].c++;
        v[i].b=v[i].a,v[i].w=1,v[i].d=v[i].mp=0;
    }
    for(int i=n+1;i<=n+m;i++)
    {
        scanf("%d%d%d%d",&v[i].a,&v[i].c,&v[i].b,&v[i].d);
        v[i].a++,v[i].b++,v[i].c++,v[i].d++;
        v[i].w=0,v[i].mp=i-n;
    }
    sort(v+1,v+n+m+1,cmpx);
    cdq(1,n+m);
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
相關文章
相關標籤/搜索