学了zkw线段树,觉得没什么必要刷专题的吧(切不动啊)。。
那先放一个模板题吧(我绝不会和你说搬了一道树状数组模板题的!!!)
题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某一个数加上x
2.求出某区间每一个数的和
输入输出格式
输入格式:
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作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
解法:zkw线段树(模板)
code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 const int N=1500005; 6 int n,m,Q,a[N]; 7 inline int read() { 8 int x=0,f=1; char ch=getchar(); 9 while (ch<'0'||ch>'9') f=(ch=='-')?-1:1,ch=getchar(); 10 while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); 11 return x*f; 12 } 13 void B() { 14 for (m=1; m<=n+1; m<<=1); 15 for (int i=m; i<=m+n-1; i++) scanf("%d",&a[i]); 16 for (int i=m-1; i; i--) a[i]=a[i<<1]+a[i<<1|1]; 17 } 18 void U(int x,int v) { 19 a[m+x-1]+=v; 20 for (int i=(m+x-1)>>1; i; i>>=1) a[i]=a[i<<1]+a[i<<1|1]; 21 } 22 int A(int l,int r) { 23 int ret=0; 24 for (l=m+l-2,r=m+r; l^r^1!=0; l>>=1,r>>=1) { 25 if (!(l&1)) ret+=a[l^1]; 26 if (r&1) ret+=a[r^1]; 27 } 28 return ret; 29 } 30 int main() { 31 n=read(),Q=read(),B(); 32 for (int i=1; i<=Q; i++) { 33 int t=read(),x=read(),y=read(); 34 if (t&1) U(x,y); else printf("%d\n",A(x,y)); 35 } 36 return 0; 37 }
zkw线段树特别清真。。