【BZOJ2683】简单题

cdq分治妙啊

(被改过题面的)原题:

dydxh所出的题目是这样的:
有一个N*N矩阵,给出一系列的修改和询问,修改是这样的:将(x,y)中的数字加上k,而询问是这样的:求(x1,y1)到(x2,y2)这个子矩阵内所有数字的和。
虽然这么高级的数据结构题mzx这种菜逼当然不会,但是由于dydxh给mzx留了一条没有强制在线的生路,所以mzx决定挑战一下这道题。

1<=N<=500000,操作数不超过200000个,操作1中的k为正整数,且不超过2000

思路很妙,知道为什么要这样做但是感觉考场上想不出来QAQ

首先询问容斥成4个前缀和问题,设时间轴为z,问题就变成询问z<qz,x<qx,y<qy里面的数总和是多少

然后就跟数星星很像了,排序x,这样右边的x保证比左边的x大,cdq分治z,树状数组y

看网上的做法和我之前想的有点不一样,我之前想的是想归并排序那样从将右边的队头和左边的队头比较,小的出队,先递归,再计算

网上比较多的做法是,先计算,左边的修改给右边的查询贡献,然后把时间轴<=mid的放到mid左边,>mid的放到右边,再递归下一层

感觉第二种对于我来说更好理解吧,比较贴合cdq分治的本质,现在还不能理解这两种写法的联系

听闵神说递归的效率非常低?我和山神的递归2.2s,闵神迭代0.4s……

还需要想一下迭代的写法啊

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 #include<queue>
 7 #include<vector>
 8 using namespace std;
 9 int read(){int z=0,mark=1;  char ch=getchar();
10     while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)mark=-1;  ch=getchar();}
11     while(ch>=‘0‘&&ch<=‘9‘){z=(z<<3)+(z<<1)+ch-‘0‘;  ch=getchar();}
12     return z*mark;
13 }
14 struct cdd{int x,y,z,v,mk;}a[810000];  int tp=0;
15 int n;
16 int e[510000],lbt[510000];
17 cdd q[810000];  int hd=0;
18 int ans[210000];
19 int t=0;
20 void gtlbt(){for(int i=1;i<=500000;++i)lbt[i]=i&-i;}
21 void mdf(int x,int y){while(x<=n)  e[x]+=y,x+=lbt[x];}
22 int qr(int x){int bwl=0;  while(x)  bwl+=e[x],x-=lbt[x];  return bwl;}
23 //int qr(int x){int bwl=0;  while(x)  bwl+=e[x],x-=lbt[x];}
24 void dfs(int l,int r){
25     if(l==r)  return ;
26     int md=(l+r)>>1;
27     for(int i=l;i<=r;++i){
28         if(!a[i].mk && a[i].z<=md)  mdf(a[i].y,a[i].v);
29         else if(a[i].mk && a[i].z>md)
30             ans[a[i].v]+=a[i].mk*qr(a[i].y);
31     }
32     for(int i=l;i<=r;++i)if(!a[i].mk && a[i].z<=md)  mdf(a[i].y,-a[i].v);
33     int t1=l,t2=md+1;
34     for(int i=l;i<=r;++i)  q[(a[i].z<=md?t1:t2)++]=a[i];
35     for(int i=l;i<=r;++i)  a[i]=q[i];
36     dfs(l,md),dfs(md+1,r);
37 }
38 bool cmp(cdd x,cdd y){return (x.x==y.x)?((x.z==y.z)?x.y<y.y:x.z<y.z):x.x<y.x;}
39 int main(){//freopen("ddd.in","r",stdin);
40     gtlbt();
41     cin>>n;
42     int mk,x,y,z,v;
43     while((mk=read())!=3){
44         if(mk==1)  a[++tp].mk=0,a[tp].x=read(),a[tp].y=read(),a[tp].v=read(),a[tp].z=tp;
45         else{
46             x=read(),y=read(),z=read(),v=read();
47             a[++tp].mk=1,a[tp].x=z,a[tp].y=v,a[tp].z=tp,a[tp].v=++t;
48             a[++tp].mk=1,a[tp].x=x-1,a[tp].y=y-1,a[tp].z=tp,a[tp].v=t;
49             a[++tp].mk=-1,a[tp].x=z,a[tp].y=y-1,a[tp].z=tp,a[tp].v=t;
50             a[++tp].mk=-1,a[tp].x=x-1,a[tp].y=v,a[tp].z=tp,a[tp].v=t;
51         }
52     }
53     sort(a+1,a+tp+1,cmp);
54     dfs(1,tp);
55     for(int i=1;i<=t;++i)  printf("%d\n",ans[i]);
56     return 0;
57 }

时间: 2024-11-09 16:41:15

【BZOJ2683】简单题的相关文章

BZOJ2683: 简单题(CDQ分治 + 树状数组)

BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ x\ y\ A\) \(1\le x,y \le N\),A是正整数 将格子\(x,y\)里的数字加上\(A\) \(2\ x1\ y1\ x2\ y2\) \(1\le x1\le x2\le N,1\le y1\le y2\le N\) 输出\(x1\ y1\ x2\ y2\)这个矩形内的数字

bzoj2683简单题

2683: 简单题 Time Limit: 50 Sec  Memory Limit: 128 MB Submit: 738  Solved: 307 [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<

bzoj2683简单题 cdq分治

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

bzoj2683: 简单题

CDQ分治,然而超过内存了 CDQ分治的思想还是很有趣的. http://www.lydsy.com/JudgeOnline/problem.php?id=2683 /************************************************************** Problem: 2683 User: 1349367067 Language: C++ Result: Accepted Time:7344 ms Memory:45028 kb ************

Bzoj2683 简单题 [CDQ分治]

Time Limit: 50 Sec  Memory Limit: 128 MBSubmit: 1071  Solved: 428 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这个矩形

【BZOJ2683】简单题 [分治][树状数组]

简单题 Time Limit: 50 Sec  Memory Limit: 128 MB[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

【BZOJ-1176&amp;2683】Mokia&amp;简单题 CDQ分治

1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 821[Submit][Status][Discuss] Description 维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000. Input 第一行两个整数,S,W;其中S为矩阵初始值;W为矩阵大小

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吃糖果时有个特殊的癖好,就是不喜欢将一样的糖果放在一起吃,喜欢先吃一种,下一次吃另一 种,这样: