P2163 [SHOI2007]园丁的烦恼(cdq分治)

思路

其实是cdq的板子

题目要求询问对于每个给出的xi,yi,xj,yj形如xi<=x<=xj.yi<=y<=yj的x,y对数有多少组

改成四个询问,拆成四个前缀和的形式后就变成熟悉的偏序问题

(query(xj,yj)-query(xj,yi))-(query(xi,yj)-query(xi,yi))

变形为

query(xj,yj)-query(xj,yi)-query(xi,yj)+query(xi,yi)后使用cdq分治套BIT的方法求解

代码

#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXL = 1e7+5;
const int MAXN = 500100;
int n,m,ans[MAXN*5],qid,aid,maxy=-1;
namespace BIT{
    int bit[MAXL<<1];
    int lowbit(int x){
        return x&(-x);
    }
    void add(int pos,int val){
        while(pos<=maxy){
            bit[pos]+=val;
            pos+=lowbit(pos);
        }
    }
    int query(int pos){
        int ans=0;
        while(pos){
            ans+=bit[pos];
            pos-=lowbit(pos);
        }
        return ans;
    }
    void clear(int pos){
        while(pos<=maxy){
            if(bit[pos])
                bit[pos]=0;
            else
                break;
            pos+=lowbit(pos);
        }
    }
};
struct Query{
    int mode,val,IorD,ansid,posx,posy;
    bool operator < (const Query &b) const{
        return posx==b.posx?mode<b.mode:posx<b.posx;
    };
}query[MAXN*5];
Query tmp[MAXN*5];
void cdq(int L,int R){
    if(R<=L+1)
        return;
    int mid=(L+R)>>1;
    cdq(L,mid);
    cdq(mid,R);
    int l=L,r=mid,tot=0;
    while(l<mid&&r<R){
        if(query[l]<query[r]){
            if(query[l].mode==1)
                BIT::add(query[l].posy,1);
            tmp[++tot]=query[l];
            l++;
        }
        else{
            if(query[r].mode==2)
                ans[query[r].ansid]+=query[r].IorD*BIT::query(query[r].posy);
            tmp[++tot]=query[r];
            r++;
        }
    }
    while(l<mid)
        tmp[++tot]=query[l++];
    while(r<R){
        if(query[r].mode==2)
                ans[query[r].ansid]+=query[r].IorD*BIT::query(query[r].posy);
        tmp[++tot]=query[r];
        r++;
    }
    for(int i=1;i<=tot;i++){
        BIT::clear(tmp[i].posy);
        query[L+i-1]=tmp[i];
        }
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++){
        int x,y;
        scanf("%d %d",&x,&y);
        x++,y++;
        maxy=max(maxy,y);
        query[++qid].mode=1;
        query[qid].posx=x;
        query[qid].posy=y;
        query[qid].val=1;
    }
    for(int i=1;i<=m;i++){
        int x1,x2,y1,y2;
        scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
        x1++,x2++,y1++,y2++;
        maxy=max(maxy,max(y1,y2)); 

        query[++qid].ansid=++aid;
        query[qid].IorD=1;
        query[qid].mode=2;
        query[qid].posx=x2;
        query[qid].posy=y2;

        query[++qid].ansid=aid;
        query[qid].IorD=-1;
        query[qid].mode=2;
        query[qid].posx=x2;
        query[qid].posy=y1-1;

        query[++qid].ansid=aid;
        query[qid].IorD=-1;
        query[qid].mode=2;
        query[qid].posx=x1-1;
        query[qid].posy=y2;

        query[++qid].ansid=aid;
        query[qid].IorD=1;
        query[qid].mode=2;
        query[qid].posx=x1-1;
        query[qid].posy=y1-1;
    }
    cdq(0,qid+1);
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-12-14 11:06  dreagonm  阅读(302)  评论(0编辑  收藏  举报