社区讨论

请求大佬支援!cdq分治模板题

学术版参与者 1已保存回复 0

讨论操作

快速查看讨论及其快照的属性,并进行相关操作。

当前回复
0 条
当前快照
1 份
快照标识符
@mhjl9jm7
此快照首次捕获于
2025/11/04 04:24
4 个月前
此快照最后确认于
2025/11/04 04:24
4 个月前
查看原帖
rt,题目在这里 以下代码完全错误,希望各位大佬抢救一下。有少许注释
CPP
#include<bits/stdc++.h>
#define N 2000010
#define ll long long
using namespace std;
int n, m, len=-1, tot=0;
int ans[N];
struct node{//x,y:坐标  opt:询问/增加  id:顺序(时间戳?)
    int x, y;
    int opt, id;
}a[N], b[N], tem[N];//b是一个副本,tem在排序时使用
int Max(int a, int b){
    return a>b?a:b;
}
struct tree{
    int m[N];
    int lowbit(int x){
        return x & (-x);
    }
    void add(int x, int y){
        for(; x<=len; x+=lowbit(x)){
            m[x] = Max(m[x], y);
        }
    }
    int ask(int x){
        int ans=-1;
        for(; x; x-=lowbit(x)){
            ans = Max(ans, m[x]);
        }
        return ans;
    }
    void clear(int x){
        for(; m[x]; x+=lowbit(x))
            m[x] = 0;
    }
}tr;
void cdq(int l, int r){//第一维时间(天生有序),第二维x,第三维y
    if(l==r) return ;
    int mid = l+r>>1;
    cdq(l, mid), cdq(mid+1, r);
    int i=l, j=mid+1, k=0;
    while(j<=r){
        while(i<=mid && b[i].x <= b[j].x){
            if(b[i].opt==1){//不是询问操作而且x比询问小,加入树状数组中维护第三维偏序
                tr.add(b[i].y, b[i].x+b[i].y);
            }
            tem[k++] = b[i++];//这里是一个归并排序?
        }
        if(b[j].opt==2)//右区间也有可能不是询问操作
            ans[b[j].id] = min(ans[b[j].id], a[j].x+a[j].y-tr.ask(a[j].y));
        tem[k++] = b[j++];
    }
    for(int k=l; k<i; k++)
        if(b[i].opt==1) tr.clear(b[i].y);//撤销
    while(i<=mid) tem[k++] = b[i++];
    for(int i=l; i<=r; i++) b[i] = tem[i];//完成排序
}
void solve(int LR, int UD){//left或right,up或down
    for(int  i=1; i<=n; i++){
        b[i] = a[i];
        if(UD) b[i].y = len-b[i].y;
        if(LR) b[i].x = len-b[i].x;
    }
    cdq(1, n);
}
int main(){
    //freopen("garbage.in", "r", stdin);
    //freopen("garbage.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++){
        scanf("%d%d", &a[i].x, &a[i].y);
        a[i].x++, a[i].y++;//因为坐标是非负数,这样可以防止坐标是0导致lowbit()出问题
        a[i].id = i; a[i].opt = 1;
        len = Max(len, Max(a[i].x, a[i].y));//翻转,找最外边界
    }
    for(int i=1; i<=m; i++){
        scanf("%d%d%d", &a[n+i].opt, &a[n+i].x, &a[n+i].y);
        a[n+i].x++; a[n+i].y++;
        len = Max(len, Max(a[n+i].x, a[n+i].y));
        if(a[n].opt==2) a[n+i].id = ++tot;//询问
        else a[n+i].id = n+i;
    }
    len++;//看题解之前根本想不到好吧,防lowbit失效
    solve(0, 0); solve(1, 0); solve(1, 1); solve(0, 1);//对于一个询问(x, y),希望点都在它的左下,所以三种翻转分别能让左上右上右下都翻到左下
    for(int i=1; i<=tot; i++)
        cout << ans[i] << endl;
    return 0;
}

回复

0 条回复,欢迎继续交流。

正在加载回复...