HDU 5126

博客围绕一组星星操作问题展开,有添加星星和查询矩形内星星数两种操作。这是一个四维带修改的偏序问题,采用CDQ分治解决,需进行两次分治,每次分治后要对元素按坐标归并排好序,离散化时注意下标从1开始,避免树状数组死循环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:一共有Q(1<=Q<=50000)组操作,操作分为两种:1.在x,y,z处添加一颗星星,2.询问以(x1,y1,z1)与(x2,y2,z2)为左上和右下顶点的矩形之间的星星数,所有坐标取值范围均为[1,1e9]。

思路:CDQ分治模板题,x,y,z和时间四维,是个四维带修改的偏序问题,所有操作按默认时间排序,将每个查询操作拆分为8个(容斥),再进行两次分治。第一次分治:将q中每个子区间按x坐标从小到大排序,将左区间元素与右区间查询放入q2中,第二次分治(嵌套在第一次分治中):将q2中每个子区间按y坐标从小到大排序,统计左区间元素对右区间查询的贡献(利用树状数组记录z值),注意每次分治结束后,需将左右区间的所有元素按相应坐标大小归并排好序。这里用的是快排,离散化的时候注意下标要从1开始而不是从0开始,否则树状数组可能会陷入死循环。

代码:

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int M = 5e5+10;

int ans[M],c[M];
///默认对时间(id)排序
struct node
{
    int x,y,z;
    int kind,id;
    node(){}
    node(int x1,int y1,int z1,int k,int i):x(x1),y(y1),z(z1),kind(k),id(i){}
};

vector<node>q,q1,q2;
vector<int>v;
void init(){
    q.clear();
    v.clear();
    memset(c,0,sizeof(c));
}
///对x排序
bool cmp(node a,node b){
    if(a.x == b.x) return a.id < b.id;
    return a.x < b.x;
}
///对y排序
bool cmp1(node a,node b){
    if(a.y == b.y) return a.id < b.id;
    return a.y < b.y;
}

int lowbit(int x){
    return x&-x;
}

void add(int x,int val){
    while(x <= v.size()){
        c[x] += val;
        x += lowbit(x);
    }
}

int getsum(int x){
    int sum = 0;
    while(x > 0){
        sum += c[x];
        x -= lowbit(x);
    }
    return sum;
}

void countstar(){
    for(int i = 0;i < q2.size();i ++){
        if(q2[i].kind == 0) add(q2[i].z,1);
        else ans[q2[i].id] += q2[i].kind*getsum(q2[i].z);
    }
    ///每次统计完后清空树状数组 
    for(int i = 0;i < q2.size();i ++)
        if(q2[i].kind == 0) add(q2[i].z,-1);
}

void cdq1(int l,int r){
    if(l >= r) return ;
    int mid = (l + r) >> 1;
    cdq1(l,mid); cdq1(mid+1,r);
    q2.clear();
    ///只有[l,mid]中的修改会对[mid+1,r]的询问产生影响
    for(int i = l;i <= mid;i ++)
        if(q1[i].kind == 0) q2.push_back(q1[i]);
    for(int i = mid+1;i <= r;i ++)
        if(q1[i].kind) q2.push_back(q1[i]);
    sort(q2.begin(),q2.end(),cmp1);
    countstar();
}

void cdq(int l,int r){
    if(l >= r) return ;
    int mid = (l + r) >> 1;
    cdq(l,mid); cdq(mid+1,r);
    q1.clear();
    for(int i = l;i <= mid;i ++)
        if(q[i].kind == 0) q1.push_back(q[i]);
    for(int i = mid+1;i <= r;i ++)
        if(q[i].kind) q1.push_back(q[i]);
    sort(q1.begin(),q1.end(),cmp);
    cdq1(0,q1.size()-1);
}


int main()
{
    int t,n,op,x,y,z,x1,y1,z1,x2,y2,z2;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        init();
        for(int i = 0;i < n;i ++){
            scanf("%d",&op);
            if(op == 1){
                scanf("%d%d%d",&x,&y,&z);
                q.push_back(node(x,y,z,0,i));
                v.push_back(z);
                ans[i] = -1;
            }
            else{
                scanf("%d%d%d%d%d%d",&x1,&y1,&z1,&x2,&y2,&z2);
                x1--; y1--; z1--;
                ///容斥 加加减减
                q.push_back(node(x1,y1,z1,-1,i));
                q.push_back(node(x2,y2,z2,1,i));
                q.push_back(node(x1,y2,z2,-1,i));
                q.push_back(node(x2,y1,z2,-1,i));
                q.push_back(node(x2,y2,z1,-1,i));
                q.push_back(node(x2,y1,z1,1,i));
                q.push_back(node(x1,y2,z1,1,i));
                q.push_back(node(x1,y1,z2,1,i));
                v.push_back(z1); v.push_back(z2);
                ans[i] = 0;
            }
        }
        ///离散化
        sort(v.begin(),v.end());
        ///v.erase(unique(v.begin(),v.end()),v.end());
        ///树状数组下标从一开始
        for(int i = 0;i < q.size();i ++)
            q[i].z = (lower_bound(v.begin(),v.end(),q[i].z)-v.begin())+1;
        cdq(0,q.size()-1);
        for(int i = 0;i < n;i ++)
            if(ans[i] != -1) printf("%d\n",ans[i]);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值