维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
三维,时间一维,x轴一维,y轴一维,
按照一维排序之后,然后用左区间更新右区间;树状数组进行维护.
这里有两种写法,
一种是 用时间分治,一种是用 x 轴分治,
用时间分治:
这种用时间分治的方法,在CDQ中不需要在排序了, 这样子省下了不少时间.
为什么不需要排序?
我们先按照x轴排序,时间在区间里是.乱序的,然后时间在 [l,mid] 中的算左区间,[mid+1, r] 的算右区间.
区间 从 l 到 r ,那么时间也是从 l 到 r, 当我们递归每一层的时候,要把时间和 l , r 对应上.
#include<bits/stdc++.h>
#define low(x) (x & (-x))
using namespace std;
const int N = 2e5+100;
const int M = 2e6+10;
struct node{int id,qid,x,y,c;
}f[N*4],g[N*4];
bool cmp(node A, node B){if (A.x != B.x) return A.x < B.x;if (A.y != B.y) return A.y < B.y;return A.id < B.id;
}
int n,m,s,tim,qtim,ans[N];
int c[M];
void add(int x, int y){for (; x <= m; x += low(x)) c[x] += y;
}
int sum(int x){int ans = 0;for (; x; x -= low(x)) ans += c[x];return ans;
}
void CDQ(int l, int r){if (l >= r) return;int mid = (l + r) >> 1;for (int i = l; i <= r; ++i){if (f[i].id <= mid && f[i].qid == -1) add(f[i].y,f[i].c); elseif (f[i].id > mid && f[i].qid != -1) ans[f[i].qid] += f[i].c*sum(f[i].y);}for (int i = l; i <= r; ++i)if (f[i].id <= mid && f[i].qid == -1) add(f[i].y,-f[i].c);int x = l, y = mid; for (int i = l; i <= r; ++i)if (f[i].id <= mid) g[x++] = f[i]; else g[++y] = f[i];for (int i = l; i <= r; ++i)f[i] = g[i];CDQ(l,mid); CDQ(mid + 1, r);
}
int main(){scanf("%d%d",&s,&m);int op,x,y,xx,yy,z;while(scanf("%d",&op)){if (op == 3) break;if (op == 1){scanf("%d%d%d",&x,&y,&z);f[++tim] = (node){tim,-1,x,y,z};} else{scanf("%d%d%d%d",&x,&y,&xx,&yy);f[++tim] = (node){tim,qtim,xx,yy,1};f[++tim] = (node){tim,qtim,x-1,yy,-1};f[++tim] = (node){tim,qtim,xx,y-1,-1};f[++tim] = (node){tim,qtim++,x-1,y-1,1};}}sort(f+1,f+tim+1,cmp);CDQ(1,tim);for (int i = 0; i < qtim; ++i)printf("%dn",ans[i]);return 0;
}/*
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3
*/
第二种写法实现就时间长了一点,
因为在 cdq中排序了,在 cdq 中,我们就是 [l,mid] 是左区间, [mid+1,r] 是右区间.用左区间去更新右区间,
然后这个时候是有序的,我们要以 x 轴为关键字排序,然后打乱区间.再进行更新.
#include<bits/stdc++.h>
#define low(x) (x & (-x))
using namespace std;
const int N = 2e5+100;
const int M = 2e6+10;
struct node{int id,qid,x,y,c;bool vis;
}f[N*4],g[N*4];
bool cmp(node A, node B){if (A.x != B.x) return A.x < B.x;if (A.y != B.y) return A.y < B.y;return A.vis < B.vis;
}
int n,m,s,tim,qtim,ans[N];
int c[M];
void add(int x, int y){for (; x <= m; x += low(x)) c[x] += y;
}
int sum(int x){int ans = 0;for (; x; x -= low(x)) ans += c[x];return ans;
}
void CDQ(int l, int r){if (l >= r) return;int mid = (l + r) >> 1;for (int i = l; i <= mid; ++i)g[i] = f[i], g[i].vis = 0;for (int i = mid+1; i <= r; ++i)g[i] = f[i], g[i].vis = 1;sort(g+l,g+r+1,cmp);for (int i = l; i <= r; ++i)if (g[i].vis == 0 && g[i].qid == -1) add(g[i].y,g[i].c); elseif (g[i].vis == 1 && g[i].qid != -1) ans[g[i].qid] += g[i].c*sum(g[i].y);for (int i = l; i <= r; ++i)if (g[i].vis == 0 && g[i].qid == -1) add(g[i].y,-g[i].c);CDQ(l,mid); CDQ(mid + 1, r);
}int main(){scanf("%d%d",&s,&m);int op,x,y,xx,yy,z;while(scanf("%d",&op)){if (op == 3) break;if (op == 1){scanf("%d%d%d",&x,&y,&z);f[++tim] = (node){tim,-1,x,y,z};} else{scanf("%d%d%d%d",&x,&y,&xx,&yy);f[++tim] = (node){tim,qtim,xx,yy,1};f[++tim] = (node){tim,qtim,x-1,yy,-1};f[++tim] = (node){tim,qtim,xx,y-1,-1};f[++tim] = (node){tim,qtim++,x-1,y-1,1};}}CDQ(1,tim);for (int i = 0; i < qtim; ++i)printf("%dn",ans[i]);return 0;
}/*
0 4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3*/
自我认为,第二种方法,是一个通用的方法,
然后第一种方法,分治的数组的值,一定要不重复,而且对应区间.
本文发布于:2024-02-04 22:18:43,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170717683560124.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |