[BOI2007]Mokia 摩基亚
link:https://www.luogu.org/problemnew/show/P4390
题意大概就是每次在二维平面上的一个点加上一个值,然后询问一个矩阵内的权值和
经典的二维数点问题
由于可以离线,所以CDQ分治即可
把矩阵询问拆成4个前缀和的形式
时间一维, x一维, y一维
经典的三维偏序问题
注意坐标从0开始,lowbit(0)=0,所以要加一个偏移量
然鹅由于一些小问题调了一下午
code:
// luogu-judger-enable-o2
#include
#define int long long
#define lowbit(x) (x & -x)
#define N 5000005
using namespace std;
struct A{
int a, b, val, o, id;
}a[N], del[N];
int cmp(A x, A y){
return x.a < y.a;
}
int tree[N], ANS[N], F[N], tot, n;
void update(int x, int y){
for(;x <= n; x += lowbit(x)) tree[x] += y;
}
int query(int x){
int ret = 0;
for(; x; x -= lowbit(x)) ret += tree[x];
return ret;
}
void cdq(int l, int r){//三维偏序板子
if(l == r) return;
int mid = (l + r) >> 1;
cdq(l, mid), cdq(mid + 1, r);
sort(a + l, a + mid + 1, cmp), sort(a + mid + 1, a + r + 1, cmp);
int szz = 0, p = l - 1;
for(int i = mid + 1; i <= r; i ++){
while(a[p + 1].a <= a[i].a && p < mid){
++ p;
if(a[p].o == 0) update(a[p].b, a[p].val), del[++ szz] = a[p];
}
if(a[i].o == 1) F[a[i].id] = 1, ANS[a[i].id] += query(a[i].b);
}
for(int i = 1; i <= szz; i ++) update(del[i].b, -del[i].val);
}
signed main(){
scanf("%lld%lld", &n, &n);
n ++;//注意!!!!!就这里我调了一下午,n要加1的偏移量
while(1){
int opt, x, y, xx, yy, z;
scanf("%lld", &opt);
if(opt == 3) break;
if(opt == 1){
scanf("%lld%lld%lld", &x, &y, &z);
x ++, y ++;//加一个偏移量
a[++ tot] = A{x, y, z, 0, tot};
}
if(opt == 2){
scanf("%lld%lld%lld%lld", &x, &y, &xx, &yy);
x ++, y ++, xx ++, yy ++;//加一个偏移量
a[++ tot] = A{xx, yy, 0, 1, tot};//把矩阵拆成4个前缀和
a[++ tot] = A{xx, y - 1, 0, 1, tot};
a[++ tot] = A{x - 1, yy, 0, 1, tot};
a[++ tot] = A{x - 1, y - 1, 0, 1, tot};
}
}
cdq(1, tot);
// for(int i = 1; i <= tot; i ++) printf("%lld ", ANS[i]); printf("\n");
for(int i = 1; i <= tot; i ++){
if(F[i]) printf("%lld\n", ANS[i] - ANS[i + 1] - ANS[i + 2] + ANS[i + 3]), i += 3;
}
return 0;
}