BZOJ 2683: 简单题 离线+CDQ分治

2683: 简单题

Time Limit: 50 Sec  Memory Limit: 128 MB
Submit: 381  Solved: 163
[ Submit][ Status][ Discuss]

Description

你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

 

命令

参数限制

内容

1 x y A

1<=x,y<=N,A是正整数

将格子x,y里的数字加上A

2 x1 y1 x2 y2

1<=x1<= x2<=N

1<=y1<= y2<=N

输出x1 y1 x2 y2这个矩形内的数字和

3

终止程序

Input

输入文件第一行一个正整数N。
接下来每行一个操作。
 

Output

对于每个2操作,输出一个对应的答案。
 

Sample Input

4
1 2 3 3
2 1 1 3 3
1 2 2 2
2 2 2 3 4
3

Sample Output

3
5

HINT

1<=N<=500000,操作数不超过200000个,内存限制20M。

对于100%的数据,操作1中的A不超过2000。

http://www.lydsy.com/JudgeOnline/problem.php?id=2683


把操作都离线出来,按x为第一关键字,y为第二关键字排序,按照读入顺序标记操作的顺序,在mid表示某个操作的时间,mid左边的操作就会影响mid右边的操作,如此进行cdq分治。查询操作拆成4个子操作。


还要继续巩固!


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

#define Q q[tot]

const int maxn = 800000 +10;

struct Node{
    int x, y, A, no, belong, op;
}q[maxn], tq[maxn];
int ans[maxn];

bool operator <(Node a, Node b){
    if (a.x == b.x && a.y == b.y) return a.op < b.op;
    if (a.x == b.x) return a.y < b.y;
    return a.x < b.x;
}

#define lowbit(x) (x&(-x))

int N;
int tree[maxn];
void update(int x, int v){
    while(x <= N){
        tree[x] += v;
        x += lowbit(x);
    }
}

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

void solve(int l, int r){
    if (l == r) return;
    int mid = (l+r)>>1;
    for(int i = l ;i <= r; i++){
        if (q[i].no <= mid && q[i].op == 1) update(q[i].y, q[i].A);
        else if (q[i].no > mid && q[i].op == 2){
            if (q[i].A){
                ans[q[i].belong] += getsum(q[i].y);
            }
            else{
                ans[q[i].belong] -= getsum(q[i].y);
            }
        }
    }
    for(int i = l; i <= r; i++){
        if (q[i].no <= mid && q[i].op == 1) update(q[i].y, -q[i].A);
    }
    int l1 = l, l2 = mid + 1;
    for(int i = l; i <= r; i++){
        if (q[i].no <= mid) tq[l1++] = q[i];
        else tq[l2++] = q[i];
    }
    for(int i = l; i <= r; i++){
        q[i] = tq[i];
    }
    solve(l, mid); solve(mid+1, r);
}


int main()
{
//    freopen("data.in", "r", stdin);
    int T = 0, op, x, y, x1, y1, A, tot = 0;
    scanf("%d", &N);
    while(scanf("%d", &op) && op!=3){
        if (op == 1){
            scanf("%d%d%d", &x, &y, &A);
            q[++tot].op = 1; Q.x = x; Q.y = y; Q.A = A; Q.no = tot;
        }
        else{
            scanf("%d%d%d%d", &x, &y, &x1, &y1);
            q[++tot].op = 2; Q.x = x-1; Q.y = y-1; Q.A = 1; Q.no = tot; Q.belong = ++T;
            q[++tot].op = 2; Q.x = x-1; Q.y = y1; Q.A = 0; Q.no = tot; Q.belong = T;
            q[++tot].op = 2; Q.x = x1; Q.y = y-1; Q.A = 0; Q.no = tot; Q.belong = T;
            q[++tot].op = 2; Q.x = x1; Q.y = y1; Q.A = 1; Q.no = tot; Q.belong = T;
        }
    }
    sort(q+1, q+1+tot);
    solve(1, tot);
    for(int i = 1; i <= T; i++){
        printf("%d\n", ans[i]);
    }

    return 0;
}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值