简单题(bzoj 1683)

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。

/*
  第一次写cdq分治,先看了2013年集训队作业中许昊然的论文,有了一点初步理解,然后又做这个题,
  感觉对cdq分治的大概思路有了一定认识。

  cdq分治要求可离线,并且各个修改操作之间互不影响,且对查询操作的贡献独立。
  我们考虑将操作分治,那么后一般操作中的修改是独立的,查询至于前一半的所有修改和后一般在它时间之前的修改有关,
  对于前一半修改可以预处理,对于后一半在它之前的,可以递归处理。 

  这个题目的数据范围二维数据结构是不好过的,所以可以考虑将某一维排序,然后用一位数据结构维护。
  我们用前缀和的思想,将求和操作理解为四个单点查询操作,然后对于每个查询操作x,y,对他有贡献的修改操作
  一定是时间在它之前的并且x比它小的,所以我们可以按照x坐标排序,然后用树状数组维护y坐标的值。
*/
#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 800010
using namespace std;
int n,tot,T,ans[N],tree[N];
struct node{
    int op,x,y,A,no,belong;
};node Q[N],tq[N];
bool cmp(const node&s1,const node&s2){
    if(s1.x==s2.x&&s1.y==s2.y) return s1.op<s2.op;
    if(s1.x==s2.x) return s1.y<s2.y;
    return s1.x<s2.x;
}
void modify(int x,int v){
    while(x<=n){
        tree[x]+=v;
        x+=x&(-x);
    }
}
int query(int x){
    int sum=0;
    while(x){
        sum+=tree[x];
        x-=x&(-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) modify(Q[i].y,Q[i].A);
        else if(Q[i].no>mid&&Q[i].op==2){
            if(Q[i].A) ans[Q[i].belong]+=query(Q[i].y);
            else ans[Q[i].belong]-=query(Q[i].y);
        }
    for(int i=l;i<=r;i++)
        if(Q[i].no<=mid&&Q[i].op==1) modify(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(){
    scanf("%d",&n);
    int opt,x,y,v,x1,y1;
    while(1){
        scanf("%d",&opt);
        if(opt==1){
            scanf("%d%d%d",&x,&y,&v);
            Q[++tot].op=1;Q[tot].x=x;Q[tot].y=y;Q[tot].A=v;Q[tot].no=tot;
        }
        else if(opt==2){
            scanf("%d%d%d%d",&x,&y,&x1,&y1);
            Q[++tot].op=2;Q[tot].x=x-1;Q[tot].y=y-1;Q[tot].A=1;Q[tot].no=tot;Q[tot].belong=++T;
            Q[++tot].op=2;Q[tot].x=x-1;Q[tot].y=y1;Q[tot].A=0;Q[tot].no=tot;Q[tot].belong=T;
            Q[++tot].op=2;Q[tot].x=x1;Q[tot].y=y-1;Q[tot].A=0;Q[tot].no=tot;Q[tot].belong=T;
            Q[++tot].op=2;Q[tot].x=x1;Q[tot].y=y1;Q[tot].A=1;Q[tot].no=tot;Q[tot].belong=T;
        }
        else break;
    }
    sort(Q+1,Q+tot+1,cmp);
    solve(1,tot);
    for(int i=1;i<=T;i++)
        printf("%d\n",ans[i]);
    return 0;
}
    
时间: 2024-08-03 19:22:41

简单题(bzoj 1683)的相关文章

【BZOJ】【4066】简单题(强制在线)

KD-Tree KD-Tree的进阶姿势戳这里 http://zyfzyf.is-programmer.com/posts/92431.html 为啥有种线段树&平衡树的即视感……(树形结构的相似性?) 每次插入之后,判断下如果某个子树的size>父亲size*0.7,那么重构一下……(替罪羊树的即视感) 查询的时候,如果当前点表示的坐标范围被查询范围完全包含,则直接返回sum: 否则:当前点若在范围内则更新答案,左子树若不全在范围外则递归进入查询,右子树同理(线段树的即视感) TLE:re

BZOJ 2683 简单题 ——CDQ分治

简单题 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define maxn 2000005 int sum[maxn]; void a

BZOJ 2508 简单题 数学算法

题目大意:维护一个平面,支持三种操作: 0.加入一条直线(给的是两点式) 1.删除一条直线 2.询问到所有直线距离平方和最小的点 题解见 http://blog.sina.com.cn/s/blog_ab8386bc0101i1nj.html 我只是贴代码供参考的- - 注意我的abcdef和题解设的不一样- - 这简单题WA了两页- - #include <cmath> #include <cstdio> #include <cstring> #include <

bzoj 4066: 简单题 kd-tree

4066: 简单题 Time Limit: 50 Sec  Memory Limit: 20 MBSubmit: 234  Solved: 82[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

bzoj 3687: 简单题

3687: 简单题 Time Limit: 10 Sec  Memory Limit: 512 MB Description 小呆开始研究集合论了,他提出了关于一个数集四个问题:1.子集的异或和的算术和.2.子集的异或和的异或和.3.子集的算术和的算术和.4.子集的算术和的异或和.    目前为止,小呆已经解决了前三个问题,还剩下最后一个问题还没有解决,他决定把这个问题交给你,未来的集训队队员来实现. Input 第一行,一个整数n.第二行,n个正整数,表示01,a2….,. Output 一行

bzoj 2683: 简单题

2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1779  Solved: 720[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<

poj2105 IP Address(简单题)

题目链接:http://poj.org/problem?id=2105 Description Suppose you are reading byte streams from any device, representing IP addresses. Your task is to convert a 32 characters long sequence of '1s' and '0s' (bits) to a dotted decimal format. A dotted decima

poj 3270 Cow Sorting 置换群 简单题

假设初始状态为 a:2 3 1 5 4 6 则目标状态为 b:1 2 3 4 5 6且下标为初始状态中的3 1 2 4 5 6(a[3],a[1]...) 将置换群写成循环的形式 (2,3,1),(5,4),6就不用移动了. 移动方式2种 1:选循环内最小的数和其他len-1个数交换 2:选整个序列最小的数和循环内最小的数交换,转到1,再换回来. #include<cstdio> #include<queue> #include<algorithm> #include&

数论 --- 简单题

吃糖果 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)Total Submission(s): 22376    Accepted Submission(s): 6396 Problem Description HOHO, 终于从Speakless手上赢走了所有的糖果,是Gardon吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一 种,这样:

HNU 12868 Island (简单题)

题目链接:http://acm.hnu.cn/online/?action=problem&type=show&id=12868&courseid=272 解题报告:输入n*m的地图,+表示土地,-表示水,要你求这个海岛的海岸线有多长,扫一遍就可以了. 1 #include<cstdio> 2 const int maxn = 2000; 3 char map[maxn][maxn]; 4 int _x[4] = {-1,0,1,0}; 5 int _y[4] = {0