社区讨论
请求大佬支援!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 条回复,欢迎继续交流。
正在加载回复...