洛谷P3374 【模板】树状数组 1(CDQ分治)

题目描述

如题,已知一个数列,你需要进行下面两种操作:

1.将某一个数加上x

2.求出某区间每一个数的和

输入输出格式

输入格式:

第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

接下来M行每行包含3个整数,表示一个操作,具体如下:

操作1: 格式:1 x k 含义:将第x个数加上k

操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

输出格式:

输出包含若干行整数,即为所有操作2的结果。

输入输出样例

输入样例#1: 复制

5 5
1 5 4 2 3
1 1 3
2 2 5
1 3 -1
1 4 2
2 1 4

输出样例#1: 复制

14
16

说明

时空限制:1000ms,128M

数据规模:

对于30%的数据:N<=8,M<=10

对于70%的数据:N<=10000,M<=10000

对于100%的数据:N<=500000,M<=500000

样例说明:

故输出结果14、16

CDQ分治维护二维偏序

第一维用排序搞掉

第二维用CDQ分治

慢的要死。。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<ctime>
 5 #include<cstdlib>
 6 using namespace std;
 7 #define ls T[now].ch[0]
 8 #define rs T[now].ch[1]
 9 const int MAXN=2*1e6+10;
10 inline char nc()
11 {
12     static char buf[MAXN],*p1=buf,*p2=buf;
13     return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXN,stdin),p1==p2)?EOF:*p1++;
14 }
15 inline int read()
16 {
17     char c=nc();int x=0,f=1;
18     while(c<‘0‘||c>‘9‘){if(c==‘-‘)f=-1;c=nc();}
19     while(c>=‘0‘&&c<=‘9‘){x=x*10+c-‘0‘,c=nc();}
20     return x*f;
21 }
22 int n,m;
23 struct node
24 {
25     int idx;//第几次询问
26     int val;//修改的值
27     int type;//操作类型
28     bool operator<( const node &a) const {
29         return idx==a.idx?type<a.type:idx<a.idx;}
30 }Q[MAXN];
31 int qidx=0;//操作的个数
32 int aidx=0;//询问的个数
33 int ans[MAXN];
34 node tmp[MAXN];
35 void CDQ(int l,int r)
36 {
37     if(r-l<=1)    return ;
38     int mid=(l+r)>>1;CDQ(l,mid);CDQ(mid,r);
39     int sum=0;
40     int p=l,q=mid,o=0;
41     while(p<mid&&q<r)
42     {
43         if(Q[p]<Q[q])
44         {
45             if(Q[p].type==1) sum+=Q[p].val;
46             tmp[o++]=Q[p++];
47         }
48         else
49         {
50             if( Q[q].type==2)    ans[Q[q].val]-=sum;
51             else if(Q[q].type==3)    ans[Q[q].val]+=sum;
52             tmp[o++]=Q[q++];
53         }
54     }
55     while(p<mid) tmp[o++]=Q[p++];
56     while(q<r)
57     {
58         if( Q[q].type==2)    ans[Q[q].val]-=sum;
59         else if(Q[q].type==3)    ans[Q[q].val]+=sum;
60         tmp[o++]=Q[q++];
61     }
62     for(int i=0;i<o;i++) Q[i+l]=tmp[i];
63 }
64 int main()
65 {
66     #ifdef WIN32
67     freopen("a.in","r",stdin);
68     #else
69     #endif
70     n=read();m=read();
71     for(int i=1;i<=n;i++)
72     {
73         Q[qidx].idx=i;
74         Q[qidx].type=1;
75         Q[qidx].val=read();++qidx;
76     }
77     for(int i=0;i<m;i++)
78     {
79         int type=read();
80         Q[qidx].type=type;
81         if(type==1)    Q[qidx].idx=read(),Q[qidx].val=read();
82         else
83         {
84             int l=read(),r=read();
85             Q[qidx].idx=l-1;Q[qidx].val=aidx;++qidx;
86             Q[qidx].type=3;Q[qidx].idx=r;Q[qidx].val=aidx;aidx++;
87         }
88         ++qidx;
89     }
90     CDQ(0,qidx);
91     for(int i=0;i<aidx;i++)    printf("%d\n",ans[i]);
92     return 0;
93 }
时间: 2024-10-24 01:25:12

洛谷P3374 【模板】树状数组 1(CDQ分治)的相关文章

[模板]树状数组1/ZKW线段树

https://www.luogu.org/problemnew/show/P3374 1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 #define rson (o<<1|1) 5 #define lson (o<<1) 6 const int N = 530000<<1;//zkw线段树只能查询(0,bit),所以只有bit-2个叶节点,bit-2<n

[模板]树状数组

OJ题号:洛谷P3374 1 #include<cstdio> 2 #include<cstring> 3 #define maxn 500000 4 int n,m; 5 struct BIT { 6 int val[maxn]; 7 BIT() { 8 memset(val,0,sizeof val); 9 } 10 int lowbit(int x) { 11 return x&-x; 12 } 13 void modify(int p,const int x) {

POJ 2299 Ultra-QuickSort (树状数组or 归并排序分治求逆序对数)

题目大意就是说帮你给一些(n个)乱序的数,让你求冒泡排序需要交换数的次数(n<=500000) 显然不能直接模拟冒泡排序,其实交换的次数就是序列的逆序对数. 由于数据范围是 0 ≤ a[i] ≤ 999,999,999所以先要离散化,然后用合适的数据结果求出逆序 可以用线段树一步一步添加a[i],每添加前查询前面添加比它的大的有多少个就可以了. 也可用树状数组,由于树状数组求的是(1...x)的数量和所以每次添加前查询i-sum(a[i])即可 树状数组: //5620K 688MS #incl

[模板]树状数组2

https://www.luogu.org/problemnew/show/P3368 1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 using namespace std; 5 #define lowbit(a) (a&(-a)) 6 7 int n, m, t[500010], bas[500010]; 8 9 inline void update(int x, int

树状数组 :单点修改,区间查询

本人水平有限,题解不到为处,请多多谅解 本蒟蒻谢谢大家观看 题目: Problem E: 树状数组 1 :单点修改,区间查询 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 231  Solved: 78[Submit][Status][Web Board] Description 给定数列 a[1],a[2],…,a[n],你需要依次进行 q个操作,操作有两类:1 i x:给定 i,x将 a[i]加上 x:2 l r:给定 l,r,求a[l]+a

【树状数组】【权值分块】bzoj2352 Stars

经典问题:二维偏序.给定平面中的n个点,求每个点左下方的点的个数. 因为 所有点已经以y为第一关键字,x为第二关键字排好序,所以我们按读入顺序处理,仅仅需要计算x坐标小于<=某个点的点有多少个就行. 这就是所说的:n维偏序,一维排序,二维树状数组,三维 分治 Or 树状数组套平衡树…… <法一>树状数组. 1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 using name

BZOJ 2738 矩阵乘法 整体二分+二维树状数组

题目大意:给定一个矩阵,多次求某个子矩阵中的第k小 分块解法见 http://blog.csdn.net/popoqqq/article/details/41356899 <论除最小割外题目解法从来与题目名称无关系列> 整体二分 Solve(x,y,S)表示处理答案在[x,y]区间内的询问集合S 预先将所有数按照大小排序 每次将[1,mid]之间的数插入树状数组 然后对于分治内部的每一个询问 去树状数组中查询相应子矩阵的数值 如果小于等于k就划分到左集合S1 否则划分到右集合S2 然后Solv

洛谷P3374 【模板】树状数组 1

P3374 [模板]树状数组 1 140通过 232提交 题目提供者HansBug 标签 难度普及/提高- 提交  讨论  题解 最新讨论 题目描述有误 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:

洛谷 P3374 【模板】树状数组 1 如题(单点修改+区间查询)

P3374 [模板]树状数组 1 时空限制1s / 128MB 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x k 含义:将第x个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内

洛谷 P3374 【模板】树状数组 1

题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x k 含义:将第x个数加上k 操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和 输出格式: 输出包含若干行整数,即为所有操作2的结果