码迷,mamicode.com
首页 > 其他好文 > 详细

题解 P2163 【[SHOI2007]园丁的烦恼】

时间:2019-09-12 21:14:51      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:lin   端点   problem   can   max   ret   拆点   solution   scanf   

题目链接

Solution [SHOI2007]园丁的烦恼

题目大意:给定\(n\)棵树的坐标,每次询问以\((a,b)\)为左下端点,\((c,d)\)为右下端点的矩形内树的数量

题目大意:常规操作先二维前缀和一下:

\(S_{i,j}\)为左下端点\((0,0)\),右上端点\((i,j)\)内的树的数量

然后每组询问的答案就是

\(ans = S_{c,d} - S_{a - 1,d} - S_{c,b-1}+S_{a-1,b-1}\)

我们的点就分为了两类:询问点和修改点

对于每个询问点,我们要求的是\(x \leq m.x\;and\;y \leq m.y\)的点的数量,这就是一个二维偏序问题,直接按\(x\)排序,然后进行\(cdq\)分治即可

我们要注意的是排序的顺序,两点\(a\),\(b\)

\(a.x = b.x\;and\;a.y = b.y\),我们把修改点放在前面
\(a.x = b.x\;and\;a.y \neq b.y\)我们按\(y\)排序
\(a.x \neq b.x\)我们按\(x\)排序

代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int maxq = 3e6;
struct Ques{
    int x,y,opt,id;//opt表示点的类型,1为修改点,0为询问点
    bool operator < (const Ques &b)const{//排序
        return x == b.x ? (y == b.y ? opt : y < b.y) : x < b.x;
    }
}ques[maxq],tmp[maxq];
int ques_tot,ans_tot,ans[maxq];
void cdq(int a,int b){//二维偏序
    if(a == b)return;
    int mid = (a + b) >> 1;
    cdq(a,mid),cdq(mid + 1,b);
    int posa = a,posb = mid + 1,pos = a,tot = 0;
    while(posa <= mid && posb <= b){
        if(ques[posa].y <= ques[posb].y)tot += ques[posa].opt,tmp[pos++] = ques[posa++];
        else ans[ques[posb].id] += tot,tmp[pos++] = ques[posb++];
    }
    while(posa <= mid)tmp[pos++] = ques[posa++];
    while(posb <= b)ans[ques[posb].id] += tot,tmp[pos++] = ques[posb++];
    for(int i = a;i <= b;i++)ques[i] = tmp[i];
}
int n,m;
int main(){
    scanf("%d %d",&n,&m);
    for(int x,y,i = 1;i <= n;i++)
        scanf("%d %d",&x,&y),ques[++ques_tot] = Ques{x,y,1,0};
    for(int a,b,c,d,i = 1;i <= m;i++){//拆点
        scanf("%d %d %d %d",&a,&b,&c,&d);
        ques[++ques_tot] = Ques{c,d,0,++ans_tot};
        ques[++ques_tot] = Ques{c,b - 1,0,++ans_tot};
        ques[++ques_tot] = Ques{a - 1,d,0,++ans_tot};
        ques[++ques_tot] = Ques{a - 1,b - 1,0,++ans_tot};
    }
    sort(ques + 1,ques + 1 + ques_tot);
    cdq(1,ques_tot);
    for(int i = 1;i + 3 <= ans_tot;i += 4)
        printf("%d\n",ans[i] - ans[i + 1] - ans[i + 2] + ans[i + 3]);
    return 0;
}

题解 P2163 【[SHOI2007]园丁的烦恼】

标签:lin   端点   problem   can   max   ret   拆点   solution   scanf   

原文地址:https://www.cnblogs.com/colazcy/p/11515107.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!